1.下载源码
源码部署:https://www.cnblogs.com/jssj/p/11631881.html
并不强求,最好是有源码(方便理解和查问题)。
2. 创建子项目
Spring项目中创建子项目:https://www.cnblogs.com/jssj/p/12329839.html
3. 案例(两个干预Spring生成Bean)
AppConfig:
package accelerate.app; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("accelerate") public class AppConfig { }
Apple
package accelerate.bean; import org.springframework.stereotype.Component; @Component public class Apple { public Apple(){ System.out.println("Apple"); } }
Test
package accelerate.bean; public class Test { public Test(){ System.out.println("构造方法-Test"); } }
AccelerateBeanFactoryPostProcessor
package accelerate.mybatis; import accelerate.bean.Test; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.stereotype.Component; @Component public class AccelerateBeanFactoryPostProcessor implements BeanFactoryPostProcessor { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("apple"); System.out.println("插手前:" + genericBeanDefinition.getBeanClassName()); genericBeanDefinition.setBeanClass(Test.class); } }
Demo
package accelerate.test; import accelerate.app.AppConfig; import accelerate.bean.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Demo { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class); System.out.println("最终生成的Bean:"+ annotationConfigApplicationContext.getBean("apple")); } }
build.gradle
group 'org.springframework'
version '3.2.19.BUILD-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile project(':spring-context')
compile project(':spring-beans')
}
运行结果:
结论: Apple类加了注解@Compnent而Test类没有加注解,最后通过getBean(Test.class)却拿到了Apple这个Bean对象。
根据调试:看到Spring源码AbstractApplicationContext 类有如下代码循环调用。
/** * author hubt * 该代码执行循环执行实现BeanFactoryPostProcessor的类的方法。 * @param postProcessors * @param beanFactory */ private void invokeBeanFactoryPostProcessors( Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanFactory(beanFactory); } }
如何修改干预Spring生成Bean的过程。
/** * author * Spring会将Bean的信息(类名,修饰符等等)写入BeanDefinition类中,并将这些BeanDefinition存放入beanDefinitionMap中。 * 该方法是根据你定义的名称获取对应存放bean信息的BeanDefinition。 * @param beanName name of the bean to find a definition for * @return * @throws NoSuchBeanDefinitionException */ @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { BeanDefinition bd = this.beanDefinitionMap.get(beanName); if (bd == null) { if (this.logger.isTraceEnabled()) { this.logger.trace("No bean named '" + beanName + "' found in " + this); } throw new NoSuchBeanDefinitionException(beanName); } return bd; }
案例二:
AppConfig
package accelerate.app; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("accelerate") public class AppConfig { }
AopTest
package accelerate.mybatis; import accelerate.service.AccelerateInvocationHandler; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; import java.lang.reflect.Proxy; @Component public class AopTest implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("cityService")){ Class<?> aClass = bean.getClass().getInterfaces()[0]; Class[] classes = new Class[]{aClass}; Object o = Proxy.newProxyInstance(AopTest.class.getClassLoader(), classes, new AccelerateInvocationHandler(bean)); return o; } return bean; } }
AccelerateInvocationHandler
package accelerate.service; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class AccelerateInvocationHandler implements InvocationHandler { Object o; public AccelerateInvocationHandler(Object o){ this.o = o; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("aop----before"); Object result = method.invoke(o); System.out.println("aop----after"); return result; } }
CityService
package accelerate.service; import org.springframework.stereotype.Component; @Component("cityService") public class CityService implements L { public CityService(){ System.out.println("构造方法----CityService"); } public void query() { System.out.println("logic---db"); } }
package accelerate.service; public interface L { public void query(); }
Demo
package accelerate.test; import accelerate.app.AppConfig; import accelerate.service.L; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Demo { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class); L bean = annotationConfigApplicationContext.getBean(L.class); bean.query(); } }
build.gradle 配置不变。
运行结果:
结论:原本CityService只是一个普通Bean,被修改成一个代理类。
源码分析如下:
/** * author hubt * 循环执行Spring的后置处理,也就是说实现或者继承BeanPostProcessors的类都会在这里被运用到 * @param existingBean the new bean instance * @param beanName the name of the bean * @return * @throws BeansException */ public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result; }
这边还运用了Java动态代理:https://www.cnblogs.com/jssj/p/11771408.html
案例三:
package accelerate1.app; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("accelerate1") public class AppConfig { }
package accelerate1.mybatis; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.stereotype.Component; @Component public class AccelerateBeanFactoryPostProcessor implements BeanFactoryPostProcessor { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("cityService"); /***将CityService,设置成自动装配的(Autowired的bytype方式)***/ genericBeanDefinition.setAutowireMode(2); } }
package accelerate1.service; import org.springframework.stereotype.Component; @Component("cityService") public class CityService{ Province province; public void setProvince(Province province) { this.province = province; } public void query() { System.out.println(province); } }
package accelerate1.service; import org.springframework.stereotype.Component; @Component public class Province { public Province(){ System.out.println("init province"); } }
package accelerate1.test; import accelerate1.app.AppConfig; import accelerate1.service.CityService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Demo1 { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class); annotationConfigApplicationContext.getBean(CityService.class).query(); } }
运行结果:
可以看到:打印了Province这个对象的信息,我们没有使用@Autowired注解进行注入,而是通过后置处理器将AutowiredMode的值修改点而进行自动注入。
AutowiredMode的值有4种:
1. no: 不注入(默认)。
2. byname: 按属性名称自动连接。Spring寻找与需要自动装配的属性同名的bean。。
3. bytype: 如果容器中恰好存在一个属性类型的bean,则使该属性自动连接。如果存在多个错误,则会引发致命异常。
4. constructor:类似于byType
但适用于构造函数参数。如果容器中不存在构造函数参数类型的一个bean,则将引发致命错误
注意:自动注入需要存在构造函数或者set方法才可以注入;而@Autowired不需要set方法,缺点:@Autowired只能注解在单个引用上。
Spring IOC 原理图:
感谢观看。