#Spring ##Spring中的Bean的生命周期过程
-
通过Bean对应的Java类的构造器或者工厂方法创建Bean实例
-
为Bean的属性设置值和对其他Bean的引用(如Spring的xml文件中该Bean配置有properties子节点)
-
将Bean实例传递给Bean后置处理器(实现BeanPostProcessor接口的类,并在Spring的xml文件中配置如下Bean标签)的postProcessBeforeInitialization()方法操作
<!-- com.abinge.spring.beans.MyBeanPostProcessor为自定义的实BeanPostProcessor接口的类 --> <!-- 该bean不用配置id,因为其对Spring容器中的全部Bean对象都会起作用进行操作处理 --> <bean class="com.abinge.spring.beans.MyBeanPostProcessor"/>
-
调用Bean的初始化方法(init-method)
-
将Bean实例传递给Bean后置处理器(实现BeanPostProcessor接口的类)的postProcessAfterInitialization()方法操作
-
使用Bean实例
-
当Spring容器关闭时,调用Bean的销毁方法(destroy-method) ###定义
-
Spring是一个开源的控制反转(Inversion of Control-IOC)和面向切面(AOP)的容器框架
-
其主要作用是简化企业开发 ###控制反转IOC
-
定义:控制反转IOC指应用本身(PersonServiceBean)不负责依赖对象(PersonDao)的创建及维护,依赖的对象的创建及维护由外部容器负责,这样对依赖对象的控制权就由应用本身转移到了外部容器,这种控制权的转移就是所谓的反转。
public class PersonServiceBean{ private PersonDao personDao = new PersonDao(); public void save(Person person){ personDao.save(person); } }
-
在上面的例子中,PersonDao是在应用内部创建及维护的,故不是控制反转。若使用控制反转的话,则上面的例子需要进行修改。 ###依赖注入(Dependency Injection-DI)
-
定义:在运行期,由外部容器动态的将依赖对象注入到组件中
-
对上述的代码进行控制反转下的修改,改为由外部容器负责创建:
-
通过setter方法进行依赖注入
//定义一个PersonServiceBean类 public class PersonServiceBean{ private PersonDao personDao; public void setPersonDaoBean(PersonDao personDao){ this.personDao = personDao; } public void save(Person person){ personDao.save(person); } } //在Spring配置文件中定义bean: //1、 <bean id="person" class="com.abinge.springtest.Person"/> <bean id="personDao" class="com.abinge.springtest.PersonDao"/> <bean id="personServiceBean" class="com.abinge.springtest.PersonServiceBean"> <property name="personDao" ref="personDao"/> </bean> //2、使用内部bean,此时PersonDao不能被其他bean使用 <bean id="person" class="com.abinge.springtest.Person"/> <bean id="personServiceBean" class="com.abinge.springtest.PersonServiceBean"> <property name="personDao"/> <bean class="com.abinge.springtest.PersonDao"/> </property> </bean> //在客户端 ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); PersonServiceBean personServiceBean = (Test)context.getBean("personServiceBean"); Person person = (Test)context.getBean("person"); personServiceBean.save(person);
-
通过构造器进行依赖注入
//定义一个PersonServiceBean类 public class PersonServiceBean{ private PersonDao personDao; public PersonServiceBean(PersonDao personDao){ this.personDao = personDao; } public void save(Person person){ personDao.save(person); } } //在Spring配置文件中定义bean: <bean id="person" class="com.abinge.springtest.Person"/> <bean id="personDao" class="com.abinge.springtest.PersonDao"/> <bean id="personServiceBean" class="com.abinge.springtest.PersonServiceBean"> <constructor-arg index="0" ref="personDao" type="personDao"/> </bean> //在客户端 ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); PersonServiceBean personServiceBean = (Test)context.getBean("personServiceBean"); Person person = (Test)context.getBean("person"); personServiceBean.save(person);
- 说明:
- 1、constructor-arg代表指定的构造器函数中的一个参数
- 2、可以利用index(参数的位置索引,从0开始),type(参数类型),ref(参数为依赖bean对象时,赋值为对应的bean标签的id),value(参数为基本数据类型时,可直接赋值)来指定唯一的构造器
- 3、如果一个bean的配置中没有constructor-arg属性,则必须利用默认的构造函数创建对象
- 4、所以在写一个javabean的时候,应该提供属性的setter方法,默认的构造器,带参数的构造器
-
使用Field注入(用于注解方式)
-
###Spring注入依赖对象的装配方式
手工装配(推荐使用)—— 存在两种编程方式
-
在xml配置文件中,通过在bean节点下配置,如上面展示的前2中注入方式
-
在Java代码中使用@Autowired或者@Resource注解的方式进行装配,但是我们需要在Spring的xml配置文件中添加如下配置:
<beans ……> <context:annotation-config/> </beans>
#####自动装配(容易出现不可预知的错误)
-
实现方式:在需要注入依赖对象的应用,在Spring的xml文件中对应bean标签中定义autowire属性
//对PersonServiceBean中的PersonServiceDao属性会按照类型自动装配注入 <bean id="personServiceBea" class="com.abinge.PersonServiceBean" autowire="byType"/>
-
autowire属性的值:
- byType——按类型装配,在容器中寻找该类型匹配的bean,如果找到多个则抛出异常,如果没有找到即属性值为null
- byName——按名称装配,在容器中寻找该名称匹配的bean,如果没有找到即属性值为null
- constructor——与byType类似,不同之处在于它应用于构造器参数,如果构造器参数中没有找到与构造器参数类型一致的bean则抛出异常
- autodetect——通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自行装配。如果发现默认的构造器,那就使用byType方式进行自行装配 #####手动装配:@Autowired和@Resource注解比较
-
@Autowired默认按照类型装配
-
可用于类的属性字段上,也可用于属性字段的setter方法上
@Autowired(required=false) @Qualifier("personDao"); private PersonDao personDao;//注解在字段上 @Autowired public void setPersonDao(PersonDao personDao){//注解在属性字段的setter方法上 this.personDao = personDao; }
-
默认情况下要求依赖对象必须存在,如果要允许依赖对象可以为null值时,可设置required属性为false
-
如果想让@Autowired按名称来装配的话,可以结合@Qualifier注解一起使用,如:
@Autowired(required=false) @Qualifier("personDao"); private PersonDao personDao;
-
-
@Resource默认按名称装配,当找不到与名称匹配的bean时,会按类型装配
-
也可用于类的属性字段上,也可用于属性字段的setter方法上
-
默认按名称装配,同时名称可以通过其本身的属性name指定,如果没有指定的话:
1、当@Resource注解注在属性字段上时,默认取字段的名称作为匹配bean名称寻找依赖对象 2、当@Resource注解注在属性的setter方法上时,默认取属性的名称作为匹配bean名称寻找依赖对象
-
@Resource默认按名称装配,当找不到与名称匹配的bean时,会按类型装配,但是如果指定了name属性,就只能按名称装配了。
-
###Spring的意义
-
通过控制反转降低组件之间的耦合度,实现软件各层之间的解耦;
Controller ——> Service ——>Dao
-
可以使用容器提供的众多服务,如:事务管理服务、消息服务等等;
-
容器提供单利模式支持,开发人员不再需要自己编写实例代码;
-
容器提供AOP技术,利用它可以很容易实现如权限拦截、运行期监控等功能;
-
容器提供的众多辅助类,使用这些类能够加快应用的开发,如:JdbcTemplate、HibernateTemple;
-
对主流的应用框架提供了集成支持,如:集成了Hibernate、JPA、Sturts等,便于应用的开发。 ###Spring实例化对象的方法
-
通过默认构造器的方法实例化:
//Test类的定义: public class Test{ public Test(){ System.out.println("create Test"); } } //在Spring配置文件中定义bean: <bean id="test" class="com.abinge.springtest.Test"/> //在客户端 ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); Test test = (Test)context.getBean("test");
在控制台将会打印”create Test” 由此可知:spring内部默认是调用了Test个类的默认的构造函数创建对象
-
通过静态工厂实例化
//Test类的定义: public class Test{ public Test(){ System.out.println("create Test"); } } //Test工厂的定义,需要在该工厂中定义一个静态的创建Test实例的方法: public class TestFactory{ public static Test getInstance(){ return new Test(); } } //在Spring配置文件中定义TestFactory的bean,而不是Test类的bean: <!--<bean id="test" class="com.abinge.springtest.Test"/>--> <bean id="testFactory" class="com.abinge.springtest.TestFactory" factory-method="getInstance"/> //在客户端 ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); Test test = (Test)context.getBean("testFactory");
-
通过实例工厂实例化
//Test类的定义: public class Test{ public Test(){ System.out.println("create Test"); } } //Test工厂的定义,需要在改工厂中定义非静态的创建Test实例的方法: public class TestFactory{ public Test getInstance(){ return new Test(); } } //在Spring配置文件中定义TestFactory的bean,用于让Spring创建该工厂对象,同时定义一个创建Test类的bean: <!--<bean id="test" class="com.abinge.springtest.Test"/>--> <bean id="testFactory" class="com.abinge.springtest.TestFactory" /> <bean id="test" factory-bean="testFactory" factory-method="getInstance"/> //在客户端 ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); Test test = (Test)context.getBean("test");
###Spring中Bean的实例化模式(或者叫:实例作用域Scope)
- singleton(Spring默认)
- 在每个Spring IOC容器中一个bean定义只有一个实例对象,也就是单例模式
- prototype
- 每次从IOC容器中获取的bean都是新的对象。 ###Spring中的Bean的实例化时机(实例对象的创建时机)
- 默认:
-
在Spring容器启动的时候创建即创建了各个Bean的实例对象,也就是在执行如下代码时创建了各个Bean的实例对象:
ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml");
-
- 调用context.getBean()方法时创建:
-
可以通过设置bean标签中的lazy-init属性设置为true,即表示该bean在context.getBean()方法被调用时才会被创建实例对象
<bean id="test" class="com.abinge.springtest.Test" lazy-init="true"/>
-
如果想对所有的bean都应用延迟初始化,可以在Spring配置文件的根节点beans设置dafault-lazy-init="true"属性:
<beans default-lazy-init="true" ……>
-
lazy-init属性有3个属性值:
- Default——相当于false,在spring容器启动的时候创建对象
- True——在context.getBean时创建对象
- False——在spring容器启动的时候创建对象 ###Spring中Bean的实例化模式(实例作用域Scope)与Spring中的Bean的实例化时机(实例创建时机)的结合说明:当scope为prototype时,始终在context.getBean()方法调用时时创建各bean实例对象
-
###Spring中Bean的初始化
-
可以在Test类中定义一个方法,用于Test实例对象创建后,对该实例对象进行数据的初始化操作
//Test类的定义: public class Test{ public Test(){ System.out.println("create Test"); } public init(){ //……相应的数据初始化代码 System.out.println("init data"); } } //在Spring配置文件中定义bean的同时,通过init-mathod属性指定数据初始化方法以完成数据初始化: <bean id="test" class="com.abinge.springtest.Test" init-mathod="init"/> //在客户端 ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); Test test = (Test)context.getBean("test");
-
执行步骤如下:
- Spring容器创建Test实例对象;
- 由Spring容器内部调用init初始化方法,也就是说先实例化,然后才会初始化;
###Spring中Bean的销毁
-
Spring中Bean的销毁时机
- 只有在Spring容器被关闭的时候,该容器中的各个Bean对象才会被销毁
- 也就是在之心context.close()方法时,该容器中的各个Bean对象才会被销毁
-
可以在Test类中定义一个方法,用于Test实例对象销毁前,对该实例对象中使用的部分资源进行关闭等操作
//Test类的定义: public class Test{ public Test(){ System.out.println("create Test"); } public void init(){ //……相应的数据初始化代码 System.out.println("init data"); } public void destory(){ //……相应的数据资源的关闭等操作代码 System.out.println("destory data"); } } //在Spring配置文件中定义bean的同时,通过destory-mathod属性指定数据资源关闭方法以完成资源的关闭: <bean id="test" class="com.abinge.springtest.Test" init-mathod="init" destory-mathod="destory"/> //在客户端 ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); Test test = (Test)context.getBean("test");
-
注意:
- destory方法是在Spring容器关闭后,Test实例对象销毁前执行;
- 如果一个bean的配置的实例化模式为”prototype”,则Spring容器不负责销毁。
###让Spring自动扫描和管理Bean
-
在Spring的xml配置文件中配置如下:
<beans ……> <!--<context:annotation-config/>--> <!--1、base-package="com.abinge":这样配置,Spring会自动扫描com.abinge包下及其子包下的java类,将这些Java类按照注解全部加载到其自己的容器中作为Bean对象进行管理--> <context:component-san base-package="com.abinge"/> <!-- 2、resource-pattern="service/*.class":具体指定Spring扫描包的路径,表示扫描com.abinge包下的子包service下的所有class文件 也就是com.abinge.service包下的class文件 --> <context:component-san base-package="com.abinge" resource-pattern="service/*.class"/> <!-- 3.通过exclude-filter和include-filter指定具体扫描路径 --> <context:component-san base-package="com.abinge" use-default-filters="false"> <!-- context:exclude-filter:通过expression属性指定排除指定包下com.abinge.service中的不扫描--> <context:exclude-filter type="annotation" expression="com.abinge.service"/> <!-- context:include-filter:通过expression属性指定只扫描指定包下com.abinge.service中的class对象 但是需要在context:component-san标签中设置属性use-default-filters="false"--> <context:include-filter type="annotation" expression="com.abinge.service"/> </context:component-san> </beans>
-
要想Spring对扫描的各java类进行管理,需要在各java类中注解标识
- @Service——业务层组件
- @Controller——控制层组件
- @Repository——数据访问组件,也就是Dao组件
- @Component——泛指组件,当组件不好归类时,使用这个注解标识
- @Scope("prototype")——设置bean的实例化模式为非单例,一般与上述各注释一并使用
- @PostConstruct——注解数据初始化的方法(原本为EJT3的注解,Spring进行了支持)
- @PreDestory——注解Bean销毁前的方法