将由程序代码直接操控的对象调用权交由容器,通过容器来装配管理对象。
IoC的实现方式:
- 依赖查找 Dependency Lookup/DL:容器提供回调接口和上下文环境给组件,程序代码则需要提供具体的查找方法。
- 依赖注入 Dependency Injection/DI:程序代码不做定位查询,这些工作由容器自行完成。依赖注入式程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序
依赖注入是目前最优秀的解耦方式,依赖注入让Spring的Bean之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起。
ApplicationContext与BeanFactory容器的区别:
这两个容器对其中Bean的创建时机不同:
- ApplicationContext容器在进行初始化时,会将其中的所有Bean(对象)进行创建;
缺点:占用系统资源(内存、cpu等)
优点:响应速度快 - BeanFactory容器中的对象,在容器初始化时并不会被创建,而是在真正获取该对象时才被创建;
缺点:相对来说,响应速度慢
有点:不多占用系统资源
一般情况下使用ApplicationContext,响应速度快,提高体验
Bean的装匹配
Bean的装配,即Bean对象的创建。容器根据代码需求创建Bean对象后再传递给代码的过程,称为Bean的装配
默认装配方式
代码通过getBean()方式从容器获取指定的Bean实例,容器首先会调用Bean类的无参构造器,创建空值的实例对象
动态工厂Bean
有时,项目中需要通过工厂类来创建Bean实例,而不能像前面一样,直接由Spring容器来装配Bean实例。使用工厂模式创建Bean实例,就会使工厂类与要创建的Bean类耦合在一起。
- 将动态工厂Bean作为普通Bean使用
将动态工厂Bean作为普通Bean来使用是指,在配置文件中注册过动态工厂Bean后,测试类直接通过getBean()获取到工厂对象,再由工厂对象调用其相应方法创建相应的目标对象。配置文件中无需注册目标对象的Bean。因为目标对象的创建不由Spring容器类管理。
工厂类
public class ServiceFactory {
public ISomeService getSomeService() {
return new SomeServiceImpl();
}
}
ISomeService.java
public interface ISomeService {
void doSome();
}
SomeServiceImpl.java
public class SomeServiceImpl implements ISomeService {
@Override
public void doSome() {
System.out.println("执行doSome()方法");
}
}
applicationContext.xml配置文件
<!--注册动态工厂-->
<bean id="factory" class="com.chen.service.ServiceFactory"/>
<!--注册service:动态工厂Bean-->
<bean id="myService" factory-bean="factory" factory-method="getSomeService"/>
</beans>
测试
@Test
public void testFactory() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
ISomeService service = (ISomeService)ac.getBean("myService");
service.doSome();
}
静态工厂Bean
applicationContext.xml配置文件
<!--注册Service:静态工厂Bean-->
<bean id="myService" class="com.chen.service.ServiceFactory" factory-method="getSomeService"/>
测试
@Test
public void testStaticFactory(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
ISomeService service = (ISomeService)ac.getBean("myService");
service.doSome();
}
Bean作用域
<!--注册service,
scope="prototype" 原型模式,其对象的创建时机不是在Spring容器初始化时创建,而是在代码中真正访问时才创建
scope="singleton" 单例模式,其对象的创建时机是在Spring容器初始化时创建,是默认值
-->
<bean id="myService" class="com.chen.service.SomeServiceImpl" scope="singleton"/>
Bean后处理器
特殊的Bean,容器中所有的Bean在初始化时,均会自动执行该类的两个方法。由于该Bean是由其它Bean自动调用执行,不是程序员手工调用,故此Bean无须id属性
在Bean后处理器类方法中,只要对Bean类与Bean类中的方法进行判断,就可实现对指定的Bean的指定方法进行功能扩展与增强。方法返回的Bean对象,即是增过的对象
代码中需要自定义Bean后处理器类,该类就是实现了接口BeanPostProcessor的类。该接口中包含两个方法,分别在目标Bean初始化完毕之前与之后执行。他们的返回值为:功能被扩展或增强后的Bean对象。
bean初始化完毕的标志:一个方法将被执行。即当该方法被执行时,表示该Bean被初始化完毕。所以Bean后处理器重两个方法的执行,是在这个方法之前之后执行。这个方法在后面将会讲到。
/*
第一参数是系统即将初始化的Bean实例,第二个参数是该Bean实例的id属性值。若Bean没有id就是name属性值
*/
//该方法会在目标Bean初始化完毕之前由容器自动调用
public Object postProcessBeforeInitialization(Object bean, String beanId) throw BeansException
//该方法会在目标Bean初始化完毕之后由容器自动调用
public Object postProcessAfterInitialization(Object bean, String beanId) throw BeansException
定制Bean的生命始末
为Bean定制初始化后的生命行为,也可以为Bean定制销毁前的生命行为。这些方法需要在Bean类中事先定义好,是方法名随意的public void 方法。
对于销毁方法的执行,需要有两个条件:
- 当前Bean需要时singleton的
- 要手工关闭容器
//手工关闭容器示例
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
((ClassPathXmlApplicationContext)ac).close();
Bean的生命周期
仅作了解,有大概的映像就行
- 执行无参构造器
- 执行setter
- 获取到bean的id=myService
- 获取到BeanFactory容器
- 执行before()方法
- Bean初始化完毕了
- 初始化完毕之后
- 执行after()方法
- 执行业务方法
- 实现接口的销毁之前
- 销毁之前
id与name属性
简记:name和id是一样的
一般情况下,命名<bean/>使用id属性,而不使用name属性。在没有id属性的情况下,name属
性与id属性作用是相同的。但当<bean/>中含有一些特殊字符时,就需要使用name属性了。
id的命名需要满足XML对id属性命名规范:必须以字母开头,可以包含字母、数字、下划线、连字符、句号、冒号
name属性值则可以包含各种字符