1.Spring的概述
Spring的出现主要是由于EJB的失败,EJB配置复杂,它需要大量的配置文件进行配置,从而造就了Spring的崛起。
在Spring中,它会认为一切Java类都是资源,而资源都是bean,容纳这些Bean的就是Spring的IOC容器,所以Spring就是基于Bean的编程。
IOC容器主要采用了控制反转,就是把Bean的控制权交给IOC容器。比如说,之前我们创建一个对象的时候都会进行new,而当我们使用了IOC容器之后,只需要进行编写配置文件或者使用注解,当我们使用的时候直接获取即可,这样极大的降低了对象之间的耦合性。
2.Spring IOC容器的层次结构
Spring IOC容器的设计主要是基于BeanFactory和ApplicationContext两个接口,其中ApplicationContext是BeanFactory的子接口之一,换句话说BeanFactory是Spring IOC容器所定义的最底层接口,而ApplicationContext是其高级接口之一,并且对BeanFactory功能做了许多有用的扩展,所以很多情况下都会使用ApplicationContext,BeanFactory不会直接使用,而是使用它作为一个上层接口,对它进行更多功能的扩展。
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
如果要对bean进行配置,则使用下面的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="source" class="com.hanxf.pojo.Source">
<property name="friut" value="橙汁"/>
<property name="sugar" value="少糖"/>
<property name="size" value="大杯"/>
</bean>
<bean id="juiceMaker" class="com.hanxf.pojo.JuiceMaker">
<property name="beverageShop" value="贡茶"/>
<property name="source" ref="source"/>
</bean>
</beans>
在这个配置文件中,配置了两个bean,这样Spring IOC容器在初始化bean的时候,就会读取配置文件,然后根据对应的描述信息生成相应的bean。
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-beans.xml");
JuiceMaker juiceMaker = (JuiceMaker)ctx.getBean("juiceMaker");
System.out.print(juiceMaker.makeJuice());
ctx.close();
根据上面的代码我们就是使用IOC容器获取bean。
3.Spring IOC容器的初始化和依赖注入
bean的定义和初始化在Spring容器中是两大步骤,它是先定义,然后进行初始化和依赖注入的。
Bean的定义分为3步:
(1)Resouce定位,这步是Spring IOC容器根据开发者的配置,进行资源定位,在Spring的开发中,通过XML或者注解都是十分常见的方式,定位的内容是开发者提供的。
(2)Bean Defination的载入,这个时候只是将Resource定位到的信息,保存到Bean定义中(BeanDefination),此时并不会创建Bean的实例。
(3)BeanDefinition的注册。这个过程就是将BeanDefiniation的信息发布到Spring IOC容器中,注意,此时仍旧没有对应的Bean实例的创建。
做完了这三步,Bean就在Spring IOC容器中被定义了,而没有被初始化,更没有完成依赖注入,也就是没有注入其配置的资源给Bean。对于初始化和依赖注入,Spring Bean还有一个配置,就是lazy-init,默认为自动初始化,如果将其设置为true,则只有当使用getBean方法获得一个Bean的时候才会进行初始化,完成依赖注入。
4.Spring Bean的生命周期
Spring IOC容器的本质目的就是为了管理Bean。对于Bean而言,在容器中存在其生命周期,它的初始化和销毁也需要一个过程,在一些需要自定义的过程中,我们可以插入代码去改变他们的一些行为,以满足特定的需求,这就需要使用到Spring Bean的生命周期的知识了。生命周期主要是为了了解Spring IOC的初始化和销毁过程,通过对他的学习就可以知道如何在初始化和销毁的时候加入自定义的方法,以满足特定的需求。
Spring IOC容器对Bean的管理还是比较复杂的,Spring IOC容器在执行了初始化和依赖注入后,会执行一定的步骤来完成初始化,通过这些步骤我们就能实现自定义初始化。
下面介绍一下生命周期的步骤;
- 如果Bean实现了接口BeanNameAware接口的setBeanName方法,那么它就会调用这个方法。
- 如果Bean实现了接口BeanFactory的setBeanFactoryAware的setBeanFactory,那么就会调用这个方法。
- 如果Bean实现了接口ApplicationContextAware的setApplicationContext方法,且Spring IOC容器也必须是一个ApplicationContext接口的实现类,那么才会调用这个方法,否则是不调用的。
- 如果Bean实现了接口BeanProcessor的postProcessBeforeInitialization方法,那么它就会调用这个方法。
- 如果Bean实现了接口BeanFactory的afterPropertiesSet方法,那么他就会调用这个方法。
- 如果bean自定义了初始化方法,它就会调用已定义的初始化方法。
- 如果Bean定义了接口BeanPostProcessor的postProcessAfterInitialization方法,完成了这些调用,这个时候Bean就完成了初始化,那么Bean就生存在SpringIOC的容器中了,使用者就可以从中获取Bean的服务。
当服务器正常关闭,或者遇到其他关闭Spring IOC容器的事件,它就会调用对应的方法完成Bean的销毁,其步骤如下:
- 如果Bean实现了接口DisposableBean的destory方法,那么就会调用它。
- 如果定义了自定义销毁方法,那么就会调用它。
有些步骤是在一些条件下才会执行的,如果不注意这些,往往就发现明明实现了一些接口,但是该方法并没有被执行。
IOC容器的最低要求是实现BeanFactory接口,而非ApplicationContext接口,如果采用了非ApplicationContext子类创建SpringIOC容器,那么即使是实现了ApplicationContextAware的setApplicationContext方法,它也不会在生命周期之中被调用。
此外还要注意这些接口是针对什么而言的,上述生命周期的接口,大部分是针对单个Bean而言的;BeanPostProcessor接口则是针对所有Bean而言的。当一个Bean实现了上述的接口,我们只需要在Spring IoC容器中定义它就行了,Spring IoC容器会自动识别,并且按上图中的顺序执行。
下面是一个完整的在Bean的生命周期的添加操作的过程:
BeanPostProcessor的实现类:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeanPostProcessorImpl implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【" + bean.getClass().getSimpleName() + "】对象" + beanName + "开始实例化");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【" + bean.getClass().getSimpleName() + "】对象" + beanName + "实例化完成");
return bean;
}
}
这样一个BeanPostProcessor就被我们实现了,它会先处理Spring IoC容器所有的Bean。
下面是一个Bean:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class JuiceMaker2 implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {
private String beverageShop = null;
private Source source = null;
public String getBeverageShop() {
return beverageShop;
}
public void setBeverageShop(String beverageShop) {
this.beverageShop = beverageShop;
}
public Source getSource() {
return source;
}
public void setSource(Source source) {
this.source = source;
}
public String makeJuice() {
String juice = "这是一杯由" + beverageShop + "饮品店,提供的" + source.getSize() + source.getSugar() + source.getFruit();
return juice;
}
public void init() {
System.out.println("【" + this.getClass().getSimpleName() + "】执行自定义初始化方法");
}
public void destroy() {
System.out.println("【" + this.getClass().getSimpleName() + "】执行自定义销毁方法");
}
@Override
public void setBeanName(String arg0) {
System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanNameAware接口的setBeanName方法");
}
@Override
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanFactoryAware接口的setBeanFactory方法");
}
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
System.out.println(
"【" + this.getClass().getSimpleName() + "】调用ApplicationContextAware接口的setApplicationContext方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("【" + this.getClass().getSimpleName() + "】调用InitializingBean接口的afterPropertiesSet方法");
}
}
这个类实现了所有生命周期所能实现的方法,以便于观察其生命周期的过程,其中init方法是自定义的初始化方法,而myDestroy方法是自定义的销毁方法,为了进一步使用这两个自定义的方法,看下面的实例代码:
<?xml version='1.0' encoding='UTF-8' ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!--BeanPostProcessor定义 -->
<bean id="beanPostProcessor" class="com.ssm.chapter9.bean.BeanPostProcessorImpl" />
<!--DisposableBean定义 -->
<bean id="disposableBean" class="com.ssm.chapter9.bean.DisposableBeanImpl" />
<bean id="source" class="com.ssm.chapter9.pojo.Source">
<property name="fruit" value="橙汁" />
<property name="sugar" value="少糖" />
<property name="size" value="大杯" />
</bean>
<bean id="juiceMaker2" class="com.ssm.chapter9.pojo.JuiceMaker2"
destroy-method="destroy" init-method="init">
<property name="beverageShop" value="贡茶" />
<property name="source" ref="source" />
</bean>
</beans>
测试方法:
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ssm.chapter9.pojo.JuiceMaker;
import com.ssm.chapter9.pojo.JuiceMaker2;
public class Chapter9Main {
public static void main(String[] args) {
testIoC();
}
public static void testCommon() {
JuiceMaker juiceMaker = new JuiceMaker();
juiceMaker.setWater("矿泉水");
juiceMaker.setFruit("橙子");
juiceMaker.setSugar("少糖");
System.out.println(juiceMaker.makeJuice());
}
public static void testIoC() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext("spring-cfg.xml");
JuiceMaker2 juiceMaker2 = (JuiceMaker2) ctx.getBean("juiceMaker2");
System.out.println(juiceMaker2.makeJuice());
ctx.close();
}
}
运行结果图: