您的位置:首页 > 编程语言 > Java开发

精通Spring 4.x企业应用开发实战——IoC(三)

2018-03-01 17:53 585 查看
IoC:控制反转,spring容器的内核——AOP、声明式事务都是在此基础上来的

理解IoC:某一接口具体实现的选择控制权从调用类中移除,转交给第三方决定,也就是由Spring容器借由Bean配置来进行控制
对IoC的理解:



IoC三种类型:
    1、构造函数注入:通过调用类的构造函数,将接口实现类通过构造函数变量传入。
MoAttack:通过构造函数注入geli的饰演者
public class MoAttack {
private Geli geli;

/**
* 注入geli的具体饰演者
* @param geli
*/
public MoAttack(Geli geli){
this.geli = geli;
}

public void cityGateAsk(){
geli.response();
}
}Director:通过构造函数注入geli的饰演者
public class Director {
public void director(){
//指定角色的饰演者
Geli geli = new LiDeHua();

//注入具体饰演者到剧本中
MoAttack moAttack = new MoAttack(geli);
moAttack.cityGateAsk();
}
}    2、属性注入:通过Setter方法完成调用类所需的注入
MoAttack:通过Setter方法注入geli饰演者

/**
* 通过Setter方法注入geli的饰演者
* @param geli
*/
public void setGeli(Geli geli){
this.geli = geli;
}

public void cityGateAsk(){
geli.response();
}Director:调用属性Setter方法注入
//调用属性Setter方法注入
moAttack.setGeli(geli);
moAttack.cityGateAsk();  3、 接口注入  :效果和属性注入无本质区别

通过容器完成依赖关系的注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--实现类实例化-->
<bean id="geli" class="com.smart.IoC.LiDeHua"/>
<bean id="MoAttack" class="com.smart.IoC.MoAttack"
p:geli-ref="geli">
</bean><!--通过geli-ref建立依赖关系-->
</beans>Java基础:
Java允许通过程序化的方式间接对Class进行操作。Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息,如构造函数、属性、方法。
public class ReflectTest {
public static Car initByDefaultConst() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//①通过类装载器获取Car对象
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class clazz = classLoader.loadClass("com.smart.reflect.Car");

//②获取类的默认构造器对象并通过它实例化Car
Constructor constructor = clazz.getDeclaredConstructor((Class[]) null);
Car car = (Car) constructor.newInstance();

//③通过反射方法设置属性
Method setBrand = clazz.getMethod("setBrand",String.class);
setBrand.invoke(car,"红旗轿车");
Method setColor = clazz.getMethod("setColor",String.class);
setColor.invoke(car,"黑色");
Method setMaxSpeed = clazz.getMethod("setMaxSpeed",Integer.class);

123f2
setMaxSpeed.invoke(car,"黑色");
return car;
}

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Car car = initByDefaultConst();
car.introduce();
}
}该例中使用的反射类:ClassLoader、Class、 Constructor、Method
类装载器ClassLoader:通过寻找类的字节码文件并构造出类在JVM内部表示对象的组件.装载工作由其子类完成。



类件被装载解析后,在JVM内拥有一个对应的java.lang.Class类述对象,该类的实例都指向这个描述对象的引用,而类描述对象又拥有指向关联ClassLoader的引用。
Java反射机制:Class反射对象描述类语义结构,可以从Class对象中获取构造函数、成员变量、方法等类元素的反射对象,并通过这些反射对象对目标类进行操作。Java的反射体系保证了可以通过程序化的方式访问目标类中的所有元素,(对于private和protected成员变量和方法,只要JVM的安全机制允许,也可以通过反射进行调用。)
BeanFactory(IoC容器)和ApplicationContext(应用上下文或Spring容器)
Bean工厂是Spring框架最核心的接口,他提供了高级IoC的配置机制,使管理不同类型的Java对象成为可能
应用上下文建立再BeanFactory基础之上,提供了更多面向应用的功能。
BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都可以直接使用ApplicationContext而非底层的BeanFactory
BeanFactory的类体系结构



BeanFactory最主要的方法getBean()——从容器中返回特定名称的Bean
通过BeanFactory启动IoC容器的时候,并不会初始化配置文件中的Bean,初始化动作发生再第一个调用时。对于单实例的Bean来说BeanFactory会缓存Bean实例,所以第二次使用getBean()获取Bean时,将直接从IoC容器的缓存中获取Bean实例。
ApplicationContext的类体系结构(ApplicationContext由BeanFactory派生出来)



ApplicationContext主要实现类是ClassPathXmlApplicationContext(从类路径下加载)和FileSystemXmlApplicationContext(从系统路径下加载)
ApplicationContext和BeanFactory初始化区别:BeanFactory初始化容器时并未实例化Bean,直到第一次访问某个Bean时才实例化目标Bean;ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean。

WebApplicationContext类体系结构:专门为web应用准备的,允许从相对于Web根目录的路径中装配配置文件完成初始化工作.



WebApplicationContext的初始化和ApplicationContext、BeanFactory有所区别,因为WebApplicationContext需要ServletContext实例,也就是必须在拥有web容器的前提下才能完成启动工作。(在web.xml中配置自启动的Servlet或定义web容器监听器)

Bean的生命周期
BeanFactory中Bean的生命周期图解



1)通过getBean()请求一个Bean时,如果容器注册了InstantiationAwareBeanPostProcessor 接口,则在Bean实例化之前调用接口的postProcessBeforeInstantiation()方法。
2)实例化Bean,如果容器注册了InstantiationAwareBeanPostProcessor 接口,Bean实例化之后,调用postProcessAfterInstantiation()方法。
3)如果Bean配置了属性信息,容器将配置值设置到Bean对应的属性中。在设置之前先调用InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues()方法。
4)设置Bean的属性,
如果实现了BeanNameAware接口,则调用setBeanName()方法,将配置文件中该Bean的名称设置Bean中。
如果实现了BeanFactoryAware接口,则调用setBeanFactory()方法,将BeanFactory容器实例设置Bean中。
5)如果BeanFactory装配了BeanPostProcessor 后处理器,则将调用Object postProcessBeforeInstantiation(Object bean,String beanName)接口方法对Bean进行加工。
6)如果Bean实现了InitializingBean接口,则将调用接口的afterPropertiesSet()方法    
7)如果<bean>中通过init-method属性定义了初始化方法,则将执行这个方法。
8)BeanPostProcessor后处理器定义了两个方法:①postProcessBeforeInstantiation()在 5)处调用;②Object postProcessBeforeInstantiation(),该方法调用时,容器再次获得对Bean进行加工处理的机会。
9)如果<bean>中指定Bean的范围为scope="protoType",则Bean返回给调用者,调用者负责Bean后续生命管理,Spring不再管理;若范围为scope="singleton",则将Bean放入Spring IoC容器的缓存池里,并将Bean的引用返回给调用者,Spring继续对这些Bean进行后续的生命管理。
10)对于scope="singleton"的情况,当容器关闭时,将触发对Bean后续生命周期的管理工作。如果Bean实现了DisposableBean接口,将调用Bean的destroy()方法。

11)对于scope="singleton"的Bean,如果通过<bean>的destroy-method属性指定了Bean的销毁方法,那么Spring将执行这个方法完成Bean资源的释放。

Bean的完整生命周期从Spring容器着手实例化Bean开始,直到最终销毁Bean。其中经历的关键点大致分为四类:


Bean自身的方法:如Bean调用构造函数实例化Bean、调用Setter设置Bean的属性值以及通过<bean>的init-method和destroy-method所指定的方法。


Bean级生命周期接口方法:BeanNameAware、BeanFacotyAware、InitializingBean和DisposableBean,这些接口方法由Bean直接实现。


容器级生命周期接口方法:图中带有

的步骤是由InstantiationAwareBeanPostProcessor和BeanPostProcessor两个接口实现的。称为实现类“后处理器”


工厂后处理器接口方法: 包括AspectJWeavingEnabler、CustomAutowireConfigurer、ConfigurationClassPostProcessor等方法,工厂后处理器也是容级的,在应用上下文装配配置文件后立即调用。
实例:
实现各种生命周期控制的Car
package com.smart.beanLifeCycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;

/**
* @author chenpeng
* @date 2018/3/1 12:56
*/
public class Car implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean {
private String brand;
private String color;
private int maxSpeed;

private BeanFactory beanFactory;
private String beanName;

public Car(){
System.out.println("调用Car构造函数");
}
public void setBrand(String brand){
System.out.println("调用setBrand设置属性。");
this.brand = brand;
}
public void introduce(){
System.out.println("brand: "+brand+",color: "+color+",maxSpeed: "+maxSpeed);
}
/**
* BeanFactoryAware接口方法
* @param beanFactory
* @throws BeansException
*/
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("调用BeanFactoryAware.setBeanFactory()方法");
this.beanFactory = beanFactory;
}
/**
* BeanNameAware接口方法
* @param beanName
*/
public void setBeanName(String beanName) {
System.out.println("调用BeanNameAware.setBeanName()方法");
this.beanName = beanName;
}

/**
* InitializingBean接口方法
* @throws Exception
*/
public void destroy() throws Exception {
System.out.println("调用InitializingBean.afterPropertiesSet()方法");
}
/**
* DisposableBean接口方法
* @throws Exception
*/
public void afterPropertiesSet() throws Exception {
System.out.println("调用DisposableBean.destroy()方法");
}
/**
* 通过<bean>的init-method属性指定初始化方法
*/
public void myInit(){
System.out.println("调用init-method所指定的myInit(),将maxSpeed设置为240");
this.maxSpeed = 240;
}
/**
* 通过<bean>的destroy-method属性指定销毁方法
*/
public void myDestroy(){
System.out.println("调用destroy-method所指定的myDestroy()方法");
}
}
Car类分别实现了BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean这些Bean级的生命周期控制接口。
InstantiationAwareBeanPostProcessor实现类:
package com.smart.beanLifeCycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

import java.beans.PropertyDescriptor;

/**
* @author chenpeng
* @date 2018/3/1 13:22
*/
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter{

/**
*在实例化Bean前调用
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//return super.postProcessBeforeInitialization(bean, beanName);

//对容器中的Car Bean进行处理
if("car".equals(beanName)){
System.out.println("InstantiationAware BeanPostProcessor. postProcessBeforeInstantiation");
}
return null;
}
/**
* 在实例化Bean后调用
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
//return super.postProcessAfterInstantiation(bean, beanName);

//对容器中的Car Bean进行处理
if("car".equals(beanName)){
System.out.println("InstantiationAware BeanPostProcessor. postProcessAfterInstantiation");
}
return true;
}

/**
*在设置某个属性时调用
*/
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
//return super.postProcessPropertyValues(pvs, pds, bean, beanName);

//对容器中的Car Bean进行处理,还可以通过pdst入参进行过滤
if("car".equals(beanName)){
System.out.println("InstantiationAwareBeanPostProcessor. postProcessPropertyValues");
}
return pvs;
}
}
BeanPostProcessor实现类:
package com.smart.beanLifeCycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
* @author chenpeng
* @date 2018/3/1 13:40
*/
public class MyBeanPostProcessor implements BeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("car")){
Car car = (Car) bean;
if (car.getColor() == null){
System.out.println("调用BeanPostProcessor.postProcessBeforeInitialization()," +
"color为空,设置为默认黑色");
car.setColor("黑色");
}
}
return bean;
}

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("car")){
Car car = (Car) bean;
if (car.getMaxSpeed() >= 200){
System.out.println("调用BeanPostProcessor.postProcessAfterInitialization()," +
"将maxSpeed调整为200");
car.setMaxSpeed(200);
}
}
return bean;
}
}

beanLifeCycle.xml:配置Car
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="com.smart.beanLifeCycle.Car"
init-method="myInit"
destroy-method="myDestroy"
p:brand="红旗"
p:maxSpeed="200"/>
</beans>运行报错:



Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'car' defined in class path resource [beanLifeCycle.xml]: Invocation of init method failed; nested exception is java.lang.NullPointerException
发现书上代码有问题:



InstantiationAwareBeanPostProcessor接口注册返回对应的bean,不然报空,容器获取不到!

正确运行:



ApplicationContext中Bean的生命周期
Bean在应用上下文中的生命周期和在BeanFactory中的生命周期类似,不同的是:①如果Bean实现了ApplicationContextAware接口,会增加一个调用该接口的方法,setApplicationContext();②ApplicationContext可以利用Java反射机制自动识别出配置文件中定义的BeanPostProcessor、InitializationAwareBeanPostProcessor和BeanFactoryPostProcessor,并自动注册到应用上下文中,而BeanFactory则需要手动调用addBeanPostProcessor()方法进行注册。(开发中常使用ApplicationContext



Bean的生命周期不但和其实现的接口有关还和Bean的作用范围有关。为了让Bean绑定在Spring框架上,推荐使用配置的方式而非接口的方式进行Bean的生命周期的控制。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring
相关文章推荐