1. Bean实例化方式
下面演示一下Spring中的Bean实例化过程。
1.1 无参构造方法方式(默认)
- 编写如下类:
1
2
3
4
5
6public class Bean1 {
public Bean1() {
super();
System.out.println("Bean1的无参构造方法执行了。。。");
}
}
在applicationContext.xml进行如下配置:
1
2<!-- 无参构造方法的方式 -->
<bean id="bean1" class="com.shoto.spring.demo2.Bean1"></bean>运行测试:
1
2
3
4
5
6
public void testBean1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//输出结果:Bean1的无参构造方法执行了。。。
Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
}注意:如果当前的类Bean1中没有无参构造方法,则会发生错误。
1.2 静态工厂实例化的方式
编写Bean2类和Bean2Factory工厂类:
1
2
3
4
5
6public class Bean2 {
public Bean2() {
super();
System.out.println("Bean2的无参构造方法执行了。。。");
}
}1
2
3
4
5
6public class Bean2Factory {
public static Bean2 createBean2() {
System.out.println("Bean2Factory中createBean2方法执行了。。。");
return new Bean2();
}
}在applicationContext.xml进行如下配置:
1
2<!--静态工厂实例化的方式 factory-method的值为Bean2Factory中的同名方法,用于调用工厂类方法-->
<bean id="bean2" class="com.shoto.spring.demo2.Bean2Factory" factory-method="createBean2"></bean>运行测试:
1
2
3
4
5
6
7
8
9
10
public void testBean2() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
/*
* 输出结果:
* Bean2Factory中createBean2方法执行了。。。
* Bean2的无参构造方法执行了。。。
*/
Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");
}
1.3 实例工厂实例化的方式
编写Bean3类和对应的实例工厂类Bean3Factory:
1
2
3
4
5
6
7public class Bean3 {
public Bean3() {
super();
System.out.println("Bean3的无参构造方法执行了。。。");
}
}1
2
3
4
5
6
7public class Bean3Factory {
public Bean3 createBean3() {
System.out.println("Bean3的实例化工厂执行了。。。");
return new Bean3();
}
}在applicationContext.xml进行如下配置:
1
2
3
4
5<!-- 实例工厂实例化方法
必须实例化工厂类(factory-bean)后才能调用工厂方法,用于实例化工厂类.
-->
<bean id="bean3Factory" class="com.shoto.spring.demo2.Bean3Factory"></bean>
<bean id="bean3" class="com.shoto.spring.demo2.Bean3" factory-bean="bean3Factory" factory-method="createBean3"></bean>运行测试同理,不再赘述。
2. 依赖注入(XML)
2.1 构造方法方式
编写User类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class User {
private Integer uid;
private String username;
private String password;
private Infor infor;
public User(Integer uid, String username, String password, Infor infor) {
super();
this.uid = uid;
this.username = username;
this.password = password;
this.infor = infor;
}
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", password=" + password + ", infor=" + infor + "]";
}
}编写Infor类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14private String gender;
private String address;
public Infor() {
super();
}
public Infor(String gender, String address) {
super();
this.gender = gender;
this.address = address;
}
//***getter,setter,toString
}在applicationContext.xml进行如下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14<!-- 构造方法方式属性注入 -->
<bean id="user" class="com.shoto.spring.demo3.User">
<!-- index的值分别代表构造方法的参数下标 -->
<constructor-arg index="0" value="001"></constructor-arg>
<constructor-arg index="1" value="张三"></constructor-arg>
<constructor-arg index="2" value="abc123!"></constructor-arg>
<!-- 这里引用Infor类的Bean,ref中的值为Infor的Bean的id值 -->
<constructor-arg index="3" ref="infor"></constructor-arg>
</bean>
<bean id="infor" class="com.shoto.spring.demo3.Infor">
<constructor-arg index="0" value="男"></constructor-arg>
<constructor-arg index="1" value="广州"></constructor-arg>
</bean>运行测试:
1
2
3
4
5
6
7
public void testConstructorDI() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);//User [uid=1, username=张三, password=abc123!, infor=Infor [gender=男, address=广州]]
}
2.2 set方法方式
在上面的User类中添加对应属性的setter方法以及无参构造方法,Spring默认使用无参构造方法来创建Bean的。
在applicationContext.xml进行如下配置:
1
2
3
4
5
6
7
8
9
10
11
12<bean id="infor" class="com.shoto.spring.demo3.Infor">
<constructor-arg index="0" value="男"></constructor-arg>
<constructor-arg index="1" value="广州"></constructor-arg>
</bean>
<!-- setter方法方式属性注入 -->
<bean id="user" class="com.shoto.spring.demo3.User">
<property name="uid" value="002"></property>
<property name="username" value="李四"></property>
<property name="password" value="123456"></property>
<property name="infor" ref="infor"></property>
</bean>运行测试同理,不再赘述。
2.3 P名称空间方式
2.3.1 写法
- 普通属性:p:属性名=”值”
- 对象属性:p:属性名-ref=”值”
2.3.2 引入
2.3.3 使用
2.4 SpEL方式
SpEL:Spring Expression Language,Spring的表达式语言。
使用语法:#{SpEL}
2.4.1 使用
1 | <!-- SpEL方式 --> |
注意:SpEL的功能远远不止用于属性的注入,它还可以进行运算、集合匹配和提供正则表达式进行匹配等,有时间在补充一下吧。
2.5 集合类型属性注入
编写CollectionBean类,如下示:
1
2
3
4
5
6
7
8
9
10
11
12public class CollectionBean {
private String[] arrs;
private List<String> list;
private Map<Integer,String> map;
private Set<String> set;
private Properties props;
public CollectionBean() {
super();
}
//***setter,getter
}applicationContext.xml的配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45<!-- Spring的集合属性注入 -->
<bean id="collection" class="com.shoto.spring.demo3.CollectionBean">
<!-- 注入数组类型 -->
<property name="arrs">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
<!-- 注入List集合类型 -->
<property name="list">
<list>
<value>Smith</value>
<value>Jack</value>
<value>Jan</value>
</list>
</property>
<!-- 注入Map集合类型 -->
<property name="map">
<map>
<entry key="1" value="aaa"/>
<entry key="2" value="bbb"/>
<entry key="3" value="ccc"/>
</map>
</property>
<!-- 注入Set集合类型 -->
<property name="set">
<set>
<value>壹</value>
<value>贰</value>
<value>叁</value>
</set>
</property>
<!-- 注入Properties集合类型 -->
<property name="props">
<props>
<prop key="prop1">prop1的值</prop>
<prop key="prop2">prop2的值</prop>
<prop key="prop3">prop3的值</prop>
</props>
</property>
</bean>上面我们都是对字符串的各个集合的装载,下面我们对自定义类进行装载。
先编写三个POJO,代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Role {
private Long id;
private String roleName;
private String note;
public Role() {
super();
}
public Role(Long id, String roleName, String note) {
super();
this.id = id;
this.roleName = roleName;
this.note = note;
}
//getter,setter,toString
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class User {
private Long id;
private String username;
private String note;
public User() {
super();
}
public User(Long id, String username, String note) {
super();
this.id = id;
this.username = username;
this.note = note;
}
//getter,setter,toString
}1
2
3
4
5
6
7public class UserRoleAssembly {
private Long id;
private List<Role> list;
private Map<Role, User> map;
private Set<Role> set;
//getter,setter
}在applicationContext.xml进行如下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51<!-- 配置Role -->
<bean id="role1" class="com.shoto.spring.demo4.Role">
<property name="id" value="1"/>
<property name="roleName" value="roleName1"/>
<property name="note" value="roleNote1"/>
</bean>
<bean id="role2" class="com.shoto.spring.demo4.Role">
<property name="id" value="2"/>
<property name="roleName" value="roleName2"/>
<property name="note" value="roleNote2"/>
</bean>
<!-- 配置User -->
<bean id="user1" class="com.shoto.spring.demo4.User">
<property name="id" value="1"/>
<property name="username" value="username1"/>
<property name="note" value="userNote1"/>
</bean>
<bean id="user2" class="com.shoto.spring.demo4.User">
<property name="id" value="2"/>
<property name="username" value="username2"/>
<property name="note" value="userNote2"/>
</bean>
<!-- 配置UserRoleAssembly-->
<bean id="userRoleAssembly" class="com.shoto.spring.demo4.UserRoleAssembly">
<property name="id" value="1"/>
<!-- 给装载有自定义对象的List集合属性注入值 -->
<property name="list">
<list>
<ref bean="role1"/>
<ref bean="role2"/>
</list>
</property>
<!-- 给装载有自定义对象的Map集合属性注入值 -->
<property name="map">
<map>
<entry key-ref="role1" value-ref="user1"/>
<entry key-ref="role2" value-ref="user2"/>
</map>
</property>
<!-- 给装载有自定义对象的Set集合属性注入值 -->
<property name="set">
<set>
<ref bean="role1"/>
<ref bean="role2"/>
</set>
</property>
</bean>测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void testCollection() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserRoleAssembly userRoleAssembly = (UserRoleAssembly) applicationContext.getBean("userRoleAssembly");
System.out.println("输出List集合:");
List<Role> list = userRoleAssembly.getList();
for (Role r : list) {
System.out.println(r);
}
System.out.println("输出Map集合:");
Map<Role, User> map = userRoleAssembly.getMap();
Set<Entry<Role, User>> entrySet = map.entrySet();
for (Entry<Role, User> entry : entrySet) {
System.out.println(entry.getKey() + "==" + entry.getValue());
}
System.out.println("输出Set集合:");
Set<Role> set = userRoleAssembly.getSet();
for (Role r : set) {
System.out.println(r);
}
}
3. IoC的注解开发
3.1 入门案例
创建Web项目,引入Jar包
注意:在Spring4版本中,除了引入基本的开发包和日志相关包以外,还需要引入aop的包。引入Spring的配置文件,即在src下创建applicationContext.xml文件
1
2
3
4
5
6
7
8
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
</beans>注意:要使用注解开发需要引入context约束,具体的内容引用自spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration下。
编写接口UserDAO和实现类UserDAOImpl
1
2
3
4
5package com.shoto.spring.demo;
public interface UserDAO {
public void save();
}1
2
3
4
5
6
7
8
9
10
11
12
13/**
* UserDAO的实现类
* @author 郑松涛
*
*/
"userDAO")//相当于<bean id="userDAO" class="com.shoto.spring.demo.UserDAOImpl"> (
public class UserDAOImpl implements UserDAO {
public void save() {
System.out.println("UserDAOImpl中实现用户保存的方法执行了。。。");
}
}注意:使用注解Componet在类添加上注解。
开启Spring的组件扫描
1
2<!-- 使用IoC的注解开发,配置组件扫描,即扫描哪些包下的哪些类在**类上**使用了注解 -->
<context:component-scan base-package="com.shoto.spring.demo" />运行测试
1
2
3
4
5
6
public void test1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDAO userDAO = (UserDAO) applicationContext.getBean("userDAO");
userDAO.save();//输出UserDAOImpl中实现用户保存的方法执行了。。。
}
3.2 注解方式依赖注入
注解方式:使用注解方式,Bean所对应的类可以没有set方法。
- 如果属性有set方法,则需要将属性注入的注解添加到set方法上;
- 如果属性没有set方法,则需要将属性注入的注解添加在属性上。
注意:注解@Value代表的是值的注入。如果同时使用注解@Value在属性和对应的setter方法,则实际使用的setter方法的注解注入的值。3.3 注解详解
3.3.1 @Component注解
该注解用于修饰一个类,将这个类交给Spring管理,这个注解有三个衍生注解,功能类似,只是分别应用于不同的MVC层,具体如下: - @Controller:web层
- @Service:service层
- @Repository:dao层
3.3.2 属性注入的注解
1. 普通属性:
@Value:用于设置好普通属性的值。
2. 对象类型的属性:
@Autowired:用于设置对象类型的属性的值,但是需要按照类型完成属性的注入,所谓按类型完成属性注入就是将与该属性的类型相同的bean注入进来,显然这是不太合理的,因为该属性如果是接口且有多个实现类,就会发生歧义而无法完成属性注入。因此可以使用@Autowired注解和@Qualifier注解的配合使用来完成按照名称属性注入。 具体用法如下(实现将UserDAOImpl2注入到UserDAOImpl中):
新建一个UserDAO的新的实现类UserDAOImpl2,代码如下:
1
2
3
4
5
6
7"userDAOImpl2")//先使用注解声明创建Bean,才能被引用 (
public class UserDAOImpl2 implements UserDAO {
public void save() {
System.out.println("UserDAOImpl2的save方法执行了");
}
}修改UserDAOImpl类如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19"userDAOImpl")//相当于<bean id="userDAOImpl" class="com.shoto.spring.demo.UserDAOImpl"> (
public class UserDAOImpl implements UserDAO {
"张三") (
private String username;
/*
* 注入UserDAOImpl2
* 相当于<property name="userDAOImpl2" ref="userDAOImpl2"/>
*/
"userDAOImpl2")//与UserDAOImpl中的@Component中的值相同 (
private UserDAO userDAO;
public void save() {
System.out.println("UserDAOImpl中实现用户保存的方法执行了。。。" + username);
userDAO.save();
}
}运行测试:
1
2
3
4
5
6
7
8
9
10
11
public void test1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDAO userDAO = (UserDAO) applicationContext.getBean("userDAOImpl");
/*
* 运行输出:
* UserDAOImpl中实现用户保存的方法执行了。。。张三
* UserDAOImpl2的save方法执行了
*/
userDAO.save();
}@Resource:相当于@AutoWired与@Qualifier的结合,完成对象类型的属性的注入,按照名称完成属性注入,常用于实际开发中。
修改上面的UserDAOImpl为如下:
注意:@Resource注解使用name属性来引用
3.3.3 Bean的其他注解
1. 生命周期相关注解
- @PostConstruct:初始化方法
- @PreDestroy:销毁方法
下面演示一些这两个注解的简单使用:
首先编写一个Customer类:
1 | "customer") //相当于<bean id="customer" class="com.shoto.spring.demo2.Customer"/> (value= |
在applicatinContext.xml开启注解扫描:
1 | <!-- 使用IoC的注解开发,配置组件扫描,即扫描哪些包下的类使用的注解 --> |
测试代码:
1 |
|
运行结果:
2. Bean作用范围相关注解
使用@Scope注解来设置作用范围,有以下4中作用域:
- singleton(单例):默认选项,Spring会采用单例模式创建这个对象,即Bean实例;
- prototype(多例):多例模式,Struts2和Spring整合一定会用到,不过现在Struts2很少用了。比如我们希望Struts2中的Action(Struts2的控制层类)有时候需要多个实例,这时就需要将Spring设置为多例模式了;
- request(请求):应用在web项目中,就是在一次请求中Spring会创建一个实例,但是不同点的请求会创建不同的实例;
- session (会话):应用在web项目中,就是在会话过程中Spring只创建一个实例
下面简单演示以下@Scope的使用:
在上面定义的Customer添加@Scope(“prototype”),如下所示:
运行测试:
1 |
|
4. IoC的XML和注解开发比较
4.1 适用场景
- XML:可以适用任何场景,结构清晰并维护方便。
- 注解:注解在有些地方是无法使用的,比如我们在引用第三包或者其他外部的接口时,这是可以使用XML的方式。而在对于自己的工程中所开发的类使用注解则会更为方便。
4.2 混合使用
推荐使用XML来管理Bean,而注解则完成属性注入。 也就是不再使用@Component等注解来声明创建Bean,而是以如下的形式直接写在XML文件中。