SpringBean详解

前言

Spring中,类的创建不再由new进行,而是交给Spring通过xml文件进行反射创建,这种叫做控制反转IoC(Inversion of Control),也叫做依赖注入DI(Dependency Injection)。

简单的Bean例子

导入maven项目
创建一个Person类,并在xml中配置bean信息

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="gbk"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<bean id="personId" class="com.ahao.javaeeDemo.Person">
<property name="name" value="张三" />
<property name="age" value="12"/>
</bean>
</beans>

在测试类中通过ApplicationContext进行创建对象

1
2
3
4
5
6
@Test
public void testGetPerson(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml");
Person p1 = ac.getBean("personId", Person.class);
System.out.println(p1.getName()+","+p1.getAge());
}

Bean的生命周期

  1. Bean先new进行实例化
  2. 然后注入属性
  3. 若实现了BeanNameAware接口,将Bean的ID传入setBeanName()方法。
  4. 若实现了BeanFactoryAware接口,将BeanFactory容器实例传入setBeanFactory()方法。
  5. 若实现了ApplicationContextAware接口,通过setApplicationContext()方法获取应用上下文。
  6. 调用BeanPostProcessor后处理器的预初始化方法。
  7. 调用InitializingBean接口afterPropertiesSet()方法。
  8. 配置文件bean标签下的init-method属性指定的方法
  9. 配置文件beans标签下的default-init-method全局属性指定的方法
  10. 调用BeanPostProcessor后处理器的预初始化后方法。
  11. 使用Bean
  12. 调用DisposableBean接口destory方法。
  13. 配置文件bean标签下的destory-method属性指定的方法
  14. 配置文件beans标签下的default-destory-method全局属性指定的方法

Bean的创建

Bean的创建都交由xml配置文件执行,获取Bean实例都是通过getBean方法进行。

普通new创建

1
2
3
<beans>
<bean id="person" class="com.ahao.javaeeDemo.bean.Person"/>
</beans>

静态工厂创建

需要一个静态工厂类

1
2
3
4
5
6
7
public class BeanFactory{
public static Person getPerson(String type){
if(type.equals("chinese")){
return new Chinese();
}
}
}

xml文件中配置,指定factory-method属性,获取实例用getBean()方法即可

1
2
3
4
5
6
<beans>
<bean id="chinese" class="com.ahao.javaeeDemo.factory.PersonFactory" factory-method="getPerson">
<constructor-arg value="chinese" />
<property name="axe" ref="steelAxe"/>
</bean>
</beans>

实例工厂创建

需要一个工厂类,注意这里和静态工厂的不同是不用static修饰方法

1
2
3
4
5
6
7
public class BeanFactory{
public Person getPerson(String type){
if(type.equals("chinese")){
return new Chinese();
}
}
}

xml文件中配置,指定factory-method属性,获取实例用getBean()方法即可

1
2
3
4
5
6
7
<beans>
<bean id="personFactory" class="com.ahao.javaeeDemo.factory.PersonFactory" />
<bean id="chinese" factory-bean="personFactory" factory-method="getPerson">
<constructor-arg value="chinese" />
<property name="axe" ref="steelAxe"/>
</bean>
</beans>

工厂Bean创建

工厂Bean继承自FactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class PersonFactory implements FactoryBean<Person> {
private Person person;

@Override
public Person getObject() throws Exception {
if(person == null){
person = new Chinese();
}
return person;
}

@Override
public Class<?> getObjectType() {
return person.getClass();
}

@Override
public boolean isSingleton() {
return true;
}
}

spring-bean.xml中配置,获取BeanFactory时使用&chinese

1
2
3
<beans>
<bean id="chinese" class="com.ahao.javaeeDemo.factory.PersonFactory" />
</beans>

和上面一样使用

1
2
3
4
5
6
7
8
@Test
public void testEvent(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml");
Person p1 = ac.getBean("chinese", Person.class);
p1.setAxe(new StoneAxe());
p1.useAxe();
System.out.print(ac.getBean("&chinese"));//获取BeanFactory
}

scope作用域

bean标签中的scope属性有五个值

  • singleton:单例模式,整个Spring容器中只有一个实例
  • prototype:原型模式,每次通过getBean方法都将产生一个新的实例
  • request:对每次request请求,都会产生一个新的实例
  • session:对每次session会话,都会产生一个新的实例
  • global sessionspring-bean-scopes-session-and-globalsession
    其中requestsession
    Servlet2.4以上要在web.xml中配置Listener
    Servlet2.4以下要在web.xml中配置Filter
    并且要导入maven项目
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <web-app>
    <listener><!--Servlet2.4以上-->
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <filter><!--Servlet2.4以下-->
    <filter-name>requestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>requestContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    </web-app>

自动装配注入

自动装配减少了配置文件的工作量,但降低了依赖关系的透明性和清晰性。
显示指定的依赖会覆盖自动装配的依赖

byName规则

bean标签添加autowire="byName"属性,当A类中有setB方法,且beans中有idbbean,则自动装配注入。

1
2
3
4
<beans>
<bean id="person" class="com.ahao.javaeeDemo.bean.Person" autoWire="byName"/>
<bean id="axe" class="com.ahao.javaeeDemo.bean.StoneAxe" />
</beans>

byType规则

bean标签添加autowire="byType"属性,当A类中有B类型的Field,且beans中只有一个B类型或者B的子类型的bean,则自动装配注入。
如果有多个匹配的bean,则抛出异常,使用autowire-candidate="false"即可忽略该bean

1
2
3
4
5
<beans>
<bean id="person" class="com.ahao.javaeeDemo.bean.Person" autoWire="byType"/>
<bean class="com.ahao.javaeeDemo.bean.StoneAxe" />
<bean id="steelAxe" class="com.ahao.javaeeDemo.bean.SteelAxe" autowire-candidate="false"/>
</beans>