关于Spring:
spring容器是Spring的核心,该容器负责管理spring中的java组件,
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");//这种方式实例化容器,容器会自动预初始化所有Bean实例
ctx.getBean("beanName");
ApplicationContext 实例正是Spring容器。
ApplicationContext 默认会实例化所有的singleton Bean
Spring容器并不强制要求被管理组件是标准的javabean。
Spring的核心机制:IOC(控制反转)和AOP(面向切面)
所谓的IOC,也可以说成是依赖倒置。当某个java实例(调用者)需要调用另一个java实例(被调用者)时,传统情况下,通过调用者来创建被调用者的实例,通常通过new来创建,
而在依赖注入的模式下创建被调用者的工作不再由调用者来完成,因此称之为"控制反转";创建被调用者实例的工作通常由Spring来完成,然后注入调用者,所以也称之为"依赖注入"。
而对于AOP,我在下一课里面再写,AOP还是比较重要的,单独写一篇比较好。
依赖注入的两种方式:
设置注入:IoC容器使用属性的setter方式注入被依赖的实例。<property name="" ref="">
构造注入:IoC容器使用构造器来注入被依赖的实例。<constructor-arg ref="">
配置构造注入的时候<constructor-arg>可以配置index属性,用于指定该构造参数值作为第几个构造参数值。下标从0开始。
Bean实例的创建方式:
①调用构造器创建Bean实例;
②调用静态工厂方法创建Bean;
③调用实例工厂创建Bean。
调用静态工厂方法创建Bean:
class属性是必须的,但此时的class并不是指定Bean实例的实现类而是静态工厂类。采用静态工厂类需要配置如下两个属性:
class静态工厂类的名字;
factory-method工厂方法(必须是静态的)。
如果静态工厂的方法有参数通过<constructor-arg/>元素知道。
调用实例工厂方法创建Bean:
使用实例工厂Bean时class属性无需指定,因Spring容器不会直接实例化该Bean,
创建Bean时需要如下属性:
factory-bean:该属性为工厂Bean的ID;
factory-method:该属性是定实例工厂的工厂方法。
JavaBean的生命周期:
①singleton与prototype的区别:
singleton:Spring可以精确的知道该Bean何时被创建、初始化、销毁。对于singleton作用域的Bean,每次客户端请求Spring容器总会返回一个共享的实例。
prototype:Spring容器仅仅负责创建Bean,当容器创建了Bean的实例后,Bean实例完全交给客户端代码管理,容器不在跟踪其生命周期。
每次客户端请求prototype作用域的Bean,都会为他创建一个新的实例,
②依赖关系注入后的行为:
Spring提供两种方法在Bean全部属性设置成功后执行特定的行为:
使用init-method属性;
该Bean实现InitializingBean接口
第一种方法:使用init-method属性指定某个方法在Bean全部属性依赖关系设置结束后自动执行。使用这种方法不需要将代码与Spring的接口耦合在一起,代码污染少;
第二种方法:实现Initializing接口,该接口有一个方法void afterPropertiesSet() throws Exception,虽然实现次接口一样可以在Bean全部属性设置成功后执行特定的行为,但是污染了代码,是侵入式设计,因此不推荐使用。
注意:如果即采用init-method属性指定初始化方法,又实现InitializingBean接口来指定初始化方法,先执行initializingBean接口中定义的方法,再执行init-method属性指定的方法。
③Bean销毁之前行为:
与定制初始化相似,Spring也提供两种方式定制Bean实例销毁之前的特定行为,如下:
使用destroy-method属性:
实现DisposableBean接口:
注意:如果即采用destroy-method属性指定销毁之前的方法,又实现DisposableBean接口来指定指定销毁之前的方法,与②类似。
④default-init-method与default-destroy-method属性,指定了所有的Bean都会执行此方法,而不是单个的Bean。
协调作用域不同步的Bean:
描述:
当Spring容器中作用域不同的Bean相互依赖时,可能出现一些问题:
当两个singleton作用域Bean存在依赖关系时,或当prototype作用依赖singleton作用域的Bean时,通过属性定义依赖关系即可。、
但是,当singleton作用域的Bean依赖prototype作用域Bean时,singleton作用域的Bean只有一次初始化的机会,他的依赖关系也只有在初始化阶段被设置,而他所依赖的prototype作用域的Bean则会不断的产生新的Bean实例。
解决方案:
第一种:部分放弃依赖注入:singleton作用域的Bean每次需要prototype作用域的Bean,则主动向容器请求新的Bean实例。
第二种:利用方法注入。
第一种方案肯定是不好的,代码主动请求新的Bean实例,必然会导致与Spring API耦合,造成代码严重污染。
通常情况下采用第二种方式。
方法注入通常使用lookup方法注入,利用lookup方法注入可以让Spring容器重写容器中Bean的抽象方法或具体方法,返回查找容器中的其他 Bean,被查找的Bean通常是non-singleton Bean(尽管也可以是singleton).
如:public class SteelAxe implements Axe{
//每执行一次加一
private int count;
public String chop(){
return ++count;
}
}
public abstract class Chinese implements Perosom{
private Axe axe;
//定义一个抽象方法,该方法将由Spring负责实现
public abstract Axe createAxe();
public voidsetAxe(Axe axe){
this axe = axe;
}
public Axe getAxe(){
return axe;
}
}
在Spring配置文件中配置:
<bean id="steelAxe" class="...SteelAxe" scope="prototype"></bean>
<bean id="chinese" class="..Chinese" >
< lookup-mehtod name="createAxe" bean="steelAxe">
<property name="axe" ref="steelAxe"/>
</bean>