Spring知识复习
先复习一下Spring Framework 的整体架构图
spring-core和spring-beans提供了 Spring Framework 的最基本部分,包括IoC(反转控制)和依赖注入特性
Context 模块是基于 Core 和 Beans 模块之上的;它使得你可以通过类似于 JNDI 注册的方式访问对象。ApplicationContext接口是 Context 模型的核心,ApplicationContext除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等
依赖注入概念
依赖注入是在某个对象实例被初始化或者从一个工厂方法被构造返回以后,再通过构造参数,工厂方法参数或者 set 方法的参数就可以设置该对象的依赖的一种 process (过程);然后是由容器将这些依赖注入到对象中的;这个过程就是反转(全名是 反转控制(IOC)) 一个 bean 靠自己通过构造方法或 Service Locator 的方式有自己去控制如何定位依赖关系,如何进行实例化的方式。
- 属性的设置是在 bean 创建以后;
- 当 bean 被设置为单例模式(singleton-scoped) 以及被设置为”预先加载”,那么一旦容器启动就会立即初始化 beans;如果不是,则会延迟到当使用到这个 bean 以后才会开始进行初始化并且进行加载。
- 初始化一个 bean 往往会导致一系列的其依赖的 bean 进行创建,就像一幅相互依赖的图;
- 要注意的是,当解析一个 bean 的时候,也许会因为去解析并加载它的依赖的时候会出现问题,所以,推荐不要使用延迟加载的方式。
//简单的xml配置
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>
//bean的集合配置
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
实现自定义bean的属性
可以通过 bean 实现InitializingBean和DisposableBean接口与 bean 的声明周期进行交互. 容器通过调用afterPropertiesSet()调用 bean 的InitializingBean方法,通过destroy()方法去调用 bean 的DisposableBean方法。
public class User implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
}
@Override
public void destroy() throws Exception {
}
}
使用@PostConstruct和@PreDestroy注解的方式实现 bean 声明周期交互式更好的方式,使得你的 bean 无需实现 Spring 额外的接口。
@PostConstruct
public void init(){
staticInstance.myService = myService;
}
@PreDestroy
public void destory(){
staticInstance.myService = myService;
}
在 Spring 内部,Spring 框架通过使用BeanPostProcessor接口的实现去处理接口的回调;如果你需要一些 Spring 容器没有提供的需要自定义的特性或者其它的生命周期相关的行为,你可以通过BeanPostProcessor接口自己实现。
BeanPostProcessor接口定义了允许你自定义实例化的逻辑,依赖解析的逻辑等等的回调方法。
org.springframework.beans.factory.config.BeanPostProcessor接口只包含两个回调方法;当某个类在容器中被注册为post-processor,当每一个 bean 实例被容器创建的时候,该post-processor将会从容器中接收到两次回调,一次是当容器在进行实例的初始化方法之前(比如在调用 InitializingBean 的 afterPropertiesSet 方法或者任何 init 方法)的回调,一次是在 bean 实例化后的回调;(我的补充,BeanPostProcessor只是在 bean 实例化之前和之后进行额外的回调操作,并不会影响 bean 的实例化过程,bean 的实例化逻辑依然是通过 Spring 容器控制的);
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
// simply return the instantiated bean as-is
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
return bean; // we could potentially return any object reference here...
}
//通过实现了BeanPostProcessor接口在bean初始化之后答应bean信息
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
return bean;
}
}
自定义FactoryBean实例化逻辑
BeanFactoryPostProcessor它的语法定义和行为和BeanPostProcessor非常相似,但是有一个重要的区别:BeanFactoryPostProcessor是在定义 bean 的元数据上进行操作,也就是说,Spring IoC 容器允许在一个 bean 实例化之前通过BeanFactoryPostProcessor读取并修改定义 bean 的元数据
FactoryBean接口是 Spring IoC 容器实例化的一个可插入的节点
@Required //该注释放在的是set方法中
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
@Autowired //也能注入多个参数
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
@Autowired(required=false) //没有找到候选bean也不会装配失败
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
@Autowired, @Inject, @Resource, 和 @Value 这些注解是通过BeanPostProcessor的实现处理的,也因此,你不能在 BeanPostProcessor or BeanFactoryPostProcessor 的 beans 中使用这些 Annotations,也因此你必须通过 XML 或者 @Bean 显示的声明它们。
@Service("a")
public class EmployeeServiceImpl implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}
@Service("b")
public class EmployeeServiceImpl1 implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}
@Controller
@RequestMapping("/emplayee.do")
public class EmployeeInfoControl {
@Autowired
@Qualifier("b") //@Qualifier表示使用对应的bean的实例
EmployeeService employeeService;
@RequestMapping(params = "method=showEmplayeeInfo")
public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response, EmployeeDto dto) {
#略
}
}
@Resource //与autowired的区别在于Resource 默认按byName自动注入,autowired按byType自动注入
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
@Repository, @Service, and @Controller是@Component的特殊例子,分别用在 persistence, service, and presentation layers;现在,你也可以使用@Component来统一注解,因为目前针对这些注解没有太多的定制化,但是最佳实践是服务层使用@Service而不是使用@Component,因为将来可能会做定制化的东西。
参考博客:
伤神的博客 Spring Core Container 源码分析一:官方文档阅读笔记