- getBeanApplicationContext 接口,是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:
- 国际化
- 通配符方式获取一组 Resource 资源
- 整合 Environment 环境(能通过它获取各种来源的配置信息)
- 事件发布与监听,实现组件之间的解耦
- 它是 ApplicationContext 的父接口
- 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactoryBeanFactory 能干点啥
- 表面上只有 getBean
- 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能,都由它的实现类提供
- 下面例子中通过反射查看了它的成员变量 singletonObjects,内部包含了所有的单例 bean
BeanFactory只是一个接口,我们需要的是它的实现类,BeanFactory默认实现类为DefaultListableBeanFactory
下面我们尝试反射调用该成员变量:
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
ConfigurableApplicationContext context = SpringApplication.run(OneMain.class, args);
//默认单例bean的注册中心
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取在beanFactory实例上singletonObjects属性集合
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
//对Bean名称进行过滤,不然会有很多的单例bean
map.entrySet().stream().filter(e->e.getKey().startsWith("dhy")).forEach(e->{
System.out.println(e.getKey()+" = "+e.getValue());
});
}
}
3.ApplicationContext 比 BeanFactory 多点啥
国际化文件均在 src/resources 目录下
messages.properties(空)
messages_en.properties
hi=Hello
messages_zh.properties
hi=你好
注意
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
GenericApplicationContext context=new GenericApplicationContext();
//自定义一个bean注册到容器中
context.registerBean("messageSource", MessageSource.class, () -> {
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
ms.setDefaultEncoding("utf-8");
ms.setBasename("messages");
return ms;
});
context.refresh();
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.CHINESE));
}
}
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
GenericApplicationContext context=new GenericApplicationContext();
//寻找多个资源,底层使用ResourcePatternResolver
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (int i = 0; i < resources.length; i++) {
System.out.println(resources[i]);
}
//查找单个资源--底层使用DefaultResourceLoader
Resource resource = context.getResource("classpath:messages.properties");
System.out.println(resource);
}
}
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
GenericApplicationContext context=new GenericApplicationContext();
String java_home = context.getEnvironment().getProperty("java_home");
System.out.println(java_home);
}
}
自定义一个事件发布对象:
public class UEvent extends ApplicationEvent {
public UEvent(Object source) {
super(source);
}
}
发布事件:
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext applicationContext = SpringApplication.run(OneMain.class, args);
//我们只要获取到了context对象,就可以在应用程序执行期间发布事件
applicationContext.publishEvent(new UEvent("你好,我是自定义事件"));
}
}
监听器:
@Component
public class UListener {
@EventListener
public void listener(UEvent event)
{
System.out.println(event.getSource());
}
}
Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考
另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来
使用演示:
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
//手动构建一个BeanDefinition
AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();
//注册到bean工厂中
beanFactory.registerBeanDefinition("config",beanDefinition);
//获取当前bean工厂中存在的bean的定义
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println(beanDefinitionNames[i]);
}
}
@Configuration
class Config{
@Bean
public Bean1 bean1(){return new Bean1();}
@Bean
public Bean2 bean2(){return new Bean2();}
}
}
为什么只有config被注册到了容器中,config里面的@Bean注解并没有被解析,显然BeanFactory并没有解析这些注解的能力,那么这些能力是who提供的呢?
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
//手动构建一个BeanDefinition
AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();
//注册到bean工厂中
beanFactory.registerBeanDefinition("config",beanDefinition);
//给BeanFactory添加一些常用的后置处理器---相当于增加了解析这些注解的能力
//这一步只是往容器中注册了一些后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//这一步才是让这些后置处理器开始工作
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class)
.values().stream().forEach(
//执行bean工厂后置处理器
beanPostProcessor->{beanPostProcessor.postProcessBeanFactory(beanFactory);
System.out.println("Bean工厂后置处理器有: "+beanPostProcessor);
});
//获取当前bean工厂中存在的bean的定义
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println(beanDefinitionNames[i]);
}
}
@Configuration
static class Config{
@Bean
public Bean1 bean1(){return new Bean1();}
@Bean
public Bean2 bean2(){return new Bean2();}
}
}
Spring的BeanFactory原始功能并没有那么丰富,但是可以通过后置处理器来增强BeanFactory的功能
上面添加的bean工厂的后置处理器是用来解析一些例如@Configuration,@Bean等注解
我们还需要让Bean的后置处理器开始工作,Bean的后置处理器一般工作在Bean的生命周期过程中
public class Bean2 {
@Autowired
private Bean1 bean1;
public Bean2() {
System.out.println("Bean2构造中...");
}
public Bean1 getBean1() {
return bean1;
}
}
public class Bean1 {
public Bean1() {
System.out.println("Bean1构造中...");
}
}
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
//手动构建一个BeanDefinition
AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();
//注册到bean工厂中
beanFactory.registerBeanDefinition("config",beanDefinition);
//给BeanFactory添加一些常用的后置处理器---相当于增加了解析这些注解的能力
//这一步只是往容器中注册了一些后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//这一步才是让这些后置处理器开始工作
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class)
.values().stream().forEach(
//执行bean工厂后置处理器
beanPostProcessor->{beanPostProcessor.postProcessBeanFactory(beanFactory);
System.out.println("Bean工厂后置处理器有: "+beanPostProcessor);
});
//添加bean后置处理器---针对bean的生命周期各个阶段提供扩展
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
//获取当前bean工厂中存在的bean的定义
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println(beanDefinitionNames[i]);
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(beanFactory.getBean(Bean2.class).getBean1());
}
@Configuration
static class Config{
@Bean
public Bean1 bean1(){return new Bean1();}
@Bean
public Bean2 bean2(){return new Bean2();}
}
}
使用到bean才会去创建,这显然表明BeanFactory是懒加载的
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
//手动构建一个BeanDefinition
AbstractBeanDefinition beanDefinition= BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();
//注册到bean工厂中
beanFactory.registerBeanDefinition("config",beanDefinition);
//给BeanFactory添加一些常用的后置处理器---相当于增加了解析这些注解的能力
//这一步只是往容器中注册了一些后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//这一步才是让这些后置处理器开始工作
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class)
.values().stream().forEach(
//执行bean工厂后置处理器
beanPostProcessor->{beanPostProcessor.postProcessBeanFactory(beanFactory);
System.out.println("Bean工厂后置处理器有: "+beanPostProcessor);
});
//添加bean后置处理器---针对bean的生命周期各个阶段提供扩展
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
//获取当前bean工厂中存在的bean的定义
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println(beanDefinitionNames[i]);
}
//预先实例化所有的bean
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(beanFactory.getBean(Bean2.class).getBean1());
}
@Configuration
static class Config{
@Bean
public Bean1 bean1(){return new Bean1();}
@Bean
public Bean2 bean2(){return new Bean2();}
}
}
后置处理器都实现了该接口,确保可以保证不同后置处理的执行顺序
order越小,优先级越高
从类路径下加载配置文件:
ClassPathXmlApplicationContext xmlApplicationContext=new ClassPathXmlApplicationContext("application.xml");
从磁盘路径加载配置文件:
FileSystemXmlApplicationContext fileSystemXmlApplicationContext=new FileSystemXmlApplicationContext("D:application.xml");
使用DefaultListableBeanFactory作为bean的注册中心,XmlBeanDefinitionReader从配置文件读取配置信息,注册到DefaultListableBeanFactory中
DefaultListableBeanFactory listableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(listableBeanFactory);
// reader.loadBeanDefinitions(new ClassPathResource("application.xml"));
reader.loadBeanDefinitions(new FileSystemResource("D:application.xml"));
基于注解方式的: 通过@Configuration标注的配置类替代原来的配置文件
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(Config.class);
String[] definitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
System.out.println("已经注册的bean定义有: ");
for (int i = 0; i < definitionNames.length; i++) {
System.out.println(definitionNames[i]);
}
}
@Configuration
static class Config{
@Bean
public Bean1 bean1(){return new Bean1();}
@Bean
public Bean2 bean2(){return new Bean2();}
}
}
因为默认注册了这些后置处理器,才可以去解析这些注解
xml配置文件中注册上面的后置处理器
<context:annotation-config/>
这个标签的作用就是往容器中注入上面那些后置处理器
用于web环境的容器:
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
AnnotationConfigServletWebApplicationContext context=new AnnotationConfigServletWebApplicationContext(WebConfig.class);
}
@Configuration
static class WebConfig{
@Bean
public ServletWebServerFactory webServerFactory(){
//tomcat环境下的web服务器工厂
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet(){
//负责请求派发的servlet
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(){
//注册上的servlet---拦截所有路径
return new DispatcherServletRegistrationBean(dispatcherServlet(),"/");
}
/**
* 把bean的名称作为访问路径
*/
@Bean("/hello")
public Controller controller(){
//DispatcherServlet拦截到请求后,将请求转发给对应的controller
return new Controller() {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
httpServletResponse.getWriter().println("大忽悠");
return null;
}
};
}
}
}
大家可以顺便联系一下springboot中内嵌tomcat是如何启动的
先看下面这段代码运行结果:
@Component("lifeCycleBean")
public class TestBean {
public TestBean() {
System.out.println("testBean的构造方法被调用");
}
@Autowired
public void autowired(@Value("${JAVA_HOME}") String home)
{
System.out.println("依赖注入得到的JAVA_HOME结果为: "+home);
}
@PostConstruct
public void init(){
System.out.println("初始化方法");
}
@PreDestroy
public void destory()
{
System.out.println("销毁");
}
}
@SpringBootApplication
public class OneMain {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
ConfigurableApplicationContext applicationContext = SpringApplication.run(OneMain.class, args);
applicationContext.close();
}
}
ApplicationContext会在容器启动的时候自动初始化所有的单例Bean
一个受 Spring 管理的 bean,生命周期主要阶段有
一些资料会提到,生命周期中还有一类 bean 后处理器:BeanPostProcessor,会在 bean 的初始化的前后,提供一些扩展逻辑。但这种说法是不完整的,见下面的演示1
ApplicationContext会自动识别容器中的BeanPostProcessor
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy");
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
//返回null,表示不进行替换
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
log.debug("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
// return false;
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");
return bean;
}
}
创建前后的增强
依赖注入前的增强
初始化前后的增强
销毁之前的增强
看问题:
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.getBean();
}
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造 " + bean);
System.out.println("依赖注入 " + bean); // @Autowired, @Resource
System.out.println("初始化 " + bean);
return bean;
}
}
}
我们通过伪代码简单模拟了一下构造,依赖注入和初始化的流程,这个流程是不变的,因此可以看做是一个模板过程
但是,如果我们在依赖注入过程中,一开始只支持了@Autowired注解的解析,现在又要增加对 @Resource注解的解析,我们可以写成下面这样子:
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.getBean();
}
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造 " + bean);
System.out.println("依赖注入 " + bean); // @Autowired, @Resource
System.out.println("对Autowired注解进行解析...");
System.out.println("对Resource注解进行解析...");
System.out.println("初始化 " + bean);
return bean;
}
}
}
那现在我们又要增加对Inject注解的解析,该怎么办呢? 难不成写成下面这样子?
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.getBean();
}
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造 " + bean);
System.out.println("依赖注入 " + bean); // @Autowired, @Resource
System.out.println("对Autowired注解进行解析...");
System.out.println("对Resource注解进行解析...");
System.out.println("对Inject注解进行解析...");
System.out.println("初始化 " + bean);
return bean;
}
}
}
这不是意味着后面如果我们想要增强功能,就需要改动getBean方法来提供对新功能的支持?
这显然是非常错误的做法,那么有没有什么方法可以很好的改进这个错误做法呢? ----模板方法模式
public class TestMethodTemplate {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Inject"));
beanFactory.getBean();
}
// 模板方法 Template Method Pattern
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造 " + bean);
System.out.println("依赖注入 " + bean); // @Autowired, @Resource
for (BeanPostProcessor processor : processors) {
processor.inject(bean);
}
System.out.println("初始化 " + bean);
return bean;
}
private List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor processor) {
processors.add(processor);
}
}
static interface BeanPostProcessor {
public void inject(Object bean); // 对依赖注入阶段的扩展
}
}
无论功能如何增强,我们都可以通过增加后置处理器来巧妙解决这个问题,是不是很方便?
模板方法就是静中有动,即整个流程中有些操作是固定不变的,但是有些操作是不确定的,我们可以用抽象方法来或者接口中的抽象方法来提供,参考上面的代码。
public class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.debug("@Autowired 生效: {}", bean2);
this.bean2 = bean2;
}
@Autowired
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.debug("@Resource 生效: {}", bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.debug("@Value 生效: {}", home);
this.home = home;
}
@PostConstruct
public void init() {
log.debug("@PostConstruct 生效");
}
@PreDestroy
public void destroy() {
log.debug("@PreDestroy 生效");
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", home='" + home + '\'' +
'}';
}
}
public class Bean2 {
}
public class Bean3 {
}
@ConfigurationProperties(prefix = "java")
public class Bean4 {
private String home;
private String version;
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return "Bean4{" +
"home='" + home + '\'' +
", version='" + version + '\'' +
'}';
}
}
这里属性绑定,会从配置文件和环境变量两个地方找,因为这里java.home和java.version在环境变量中都存在,因此我们不需要在配置文件中配置任何内容,这里就可以绑定
public class A04 {
public static void main(String[] args) {
// ⬇️GenericApplicationContext 是一个【干净】的容器
//不会像AnnotationConfigApplicationContext一样自动给我们添加一些后置处理器
GenericApplicationContext context = new GenericApplicationContext();
// ⬇️用原始方法注册三个 bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4", Bean4.class);
//配合autowired和value注解解析值注入类型,例如string类型的值注入
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// @Autowired @Value
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// @Resource @PostConstruct @PreDestroy
context.registerBean(CommonAnnotationBeanPostProcessor.class);
//解析ConfigurationProperties注解
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
// ⬇️初始化容器
context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例
System.out.println(context.getBean(Bean4.class));
// ⬇️销毁容器
context.close();
/*
学到了什么
a. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能
b. 这些扩展功能由 bean 后处理器来完成
*/
}
}
注意该解析器不是用来解析{}大括号的,而是解析这种值注入类型的,否则会把String当做bean对象看待,如上所示: 这河里吗?
当然该解析器不只这个功能,目前通过我们的测试,只发现了这个功能,后续我们会专门探讨一下该解析器
// AutowiredAnnotationBeanPostProcessor 运行分析
public class DigInAutowired {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// registerSingleton方法会忽略: 创建过程,依赖注入,初始化---相当于直接提供bean的成品
beanFactory.registerSingleton("bean2", new Bean2());
beanFactory.registerSingleton("bean3", new Bean3());
// @Value---值解析器
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// ${} 的解析器
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
//与Bean工厂关联----需要到容器找寻找一些Bean进行依赖注入
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
//此时后置处理器没有工作
System.out.println(bean1);
//执行依赖注入@Autowired @Value
//第一个参数是手动指定值,而不通过依赖注入,这里我们不需要手动指定,而是通过去容器中找,进行依赖注入
//postProcessProperties方法会在bean生命周期中的依赖注入阶段被执行
processor.postProcessProperties(null,bean1,"bean1");
System.out.println(bean1);
}
}
看一下postProcessProperties方法的源码:
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// registerSingleton方法会忽略: 创建过程,依赖注入,初始化---相当于直接提供bean的成品
beanFactory.registerSingleton("bean2", new Bean2());
beanFactory.registerSingleton("bean3", new Bean3());
// @Value---值解析器
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// ${} 的解析器
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
//与Bean工厂关联----需要到容器找寻找一些Bean进行依赖注入
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
//此时后置处理器没有工作
System.out.println(bean1);
//执行依赖注入@Autowired @Value
//第一个参数是手动指定值,而不通过依赖注入,这里我们不需要手动指定,而是通过去容器中找,进行依赖注入
// processor.postProcessProperties(null,bean1,"bean1");
// System.out.println(bean1);
//反射调用findAutowiringMetadata方法,来获取返回值封装的InjectionMetadata信息
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class,
Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
InjectionMetadata injectionMetadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);
System.out.println(injectionMetadata);
}
由于InjectionMetadata 没有重写toString方法,因此我们通过断点查看
调用InjectionMetadata的inject方法,完成依赖注入
// AutowiredAnnotationBeanPostProcessor 运行分析
public class DigInAutowired {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// registerSingleton方法会忽略: 创建过程,依赖注入,初始化---相当于直接提供bean的成品
beanFactory.registerSingleton("bean2", new Bean2());
beanFactory.registerSingleton("bean3", new Bean3());
// @Value---值解析器
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// ${} 的解析器
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
//与Bean工厂关联----需要到容器找寻找一些Bean进行依赖注入
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
//此时后置处理器没有工作
System.out.println(bean1);
//执行依赖注入@Autowired @Value
//第一个参数是手动指定值,而不通过依赖注入,这里我们不需要手动指定,而是通过去容器中找,进行依赖注入
// processor.postProcessProperties(null,bean1,"bean1");
// System.out.println(bean1);
//反射调用findAutowiringMetadata方法,来获取返回值封装的InjectionMetadata信息
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class,
Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息
InjectionMetadata injectionMetadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);
//调用InjectionMetadata的inject方法,完成依赖注入
injectionMetadata.inject(bean1,"bean1",null);
System.out.println(bean1);
}
}
injectionMetadata中的inject方法的源码分析:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
//调用InjectedElement 的inject方法---这里实际上应该是AutowiredFieldElement
element.inject(target, beanName, pvs);
}
}
}
AutowiredFieldElement 是AutowiredAnnotationBeanPostProcessor的一个内部类,它里面的inject方法
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
//inject方法源码:
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
resolveFieldValue方法中都会用到一个叫做DependencyDescriptor的依赖注入描述符号
成员变量依赖bean查找:
//3.按照类型查找
Field bean3 = Bean1.class.getDeclaredField("bean3");
//封装依赖关系---->需要bean3类型的bean,并且required=false
DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(bean3, false);
//目标类型的bean---通过依赖关系,去容器中找到该类型的bean
Object targetBean = beanFactory.doResolveDependency(dependencyDescriptor, null, null,null);
System.out.println(targetBean);
方法参数依赖查找:
这里是按照方法参数为单位去容器中寻找对应的依赖关系
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
//封装方法参数描述符
DependencyDescriptor dd2 =
new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
//解析,获取依赖的bean
Object o1 = beanFactory.doResolveDependency(dd2, null, null, null);
System.out.println(o1);
如果不像容器中放入bean2类型的bean对象:
// registerSingleton方法会忽略: 创建过程,依赖注入,初始化---相当于直接提供bean的成品
// beanFactory.registerSingleton("bean2", new Bean2());
beanFactory.registerSingleton("bean3", new Bean3());
值注入
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), false);
Object o2 = beanFactory.doResolveDependency(dd3, null, null, null);
System.out.println(o2);
这里是去环境变量中寻找JAVA_HOME的值
未完待续…