文章目录
- Bean 相关
- 到底什么是`beanFactory`
- `beanFactory`能干啥
- `ApplicationContext`是什么
- `ApplicationContext`的功能比 `BeanFactory`多了什么
- 容器的实现
- `BeanFactory`的实现
- `ApplicationContext`的实现
- `xml` 配置
- 配置类配置
- Bean 的生命周期
- 3.1 Bean 的常见的后处理器
- 测试代码
- 总结
- 3.2 工厂后处理器的模拟实现
- 3.3 `Aware` 接口以及 `InitializingBean`
- 3.4 AutoWired 以及 PostConstruct 失效的情况分析
:::info
环境
- springboot2.7.18
- jdk17
:::
springboot 进入 debug 模式的三种方式
java –jar xxx.jar --debug
application.properties
中设置debug=true
- 在
idea
启动上面设置Run Configurations…
在VM arguments
中添加–Ddebug
Bean 相关
到底什么是beanFactory
:::info
它是 ApplicationContext
的父接口,是Spring
的核心容器。
:::
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) 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);
}
beanFactory
能干啥
:::info
表面上只有 getBean()
, 实际上控制反转,基本的依赖注入以及bean
的生命周期等各种功能,都由它的实现类实现。
:::
ApplicationContext
是什么
:::info
ApplicationContext
是beanFactory
的继承与扩展关系。
:::
ApplicationContext
的功能比 BeanFactory
多了什么
:::info
ApplicationContext 除了继承 BeanFactory 外,还继承了:
- MessageSource:使其具备处理国际化资源的能力
- ResourcePatternResolver:使其具备使用通配符进行资源匹配的能力
- EnvironmentCapable:使其具备读取 Spring 环境信息、配置文件信息的能力
- ApplicationEventPublisher:使其具备发布事件的能力 (事件的发布是堵塞同步的哟)
:::
ConfigurableApplicationContext context = SpringApplication.run(ShowBeanApplication.class, args);
// 只加载类路径下面的文件
Resource[] resources = context.getResources("classpath:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
System.out.println(resource.getURL());
}
System.out.println("************");
// 包含jar包的文件
Resource[] jarResources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource jarResource : jarResources) {
System.out.println(jarResource);
}
ConfigurableEnvironment environment = context.getEnvironment();
// 获取系统环境变量
Map<String, Object> systemEnvironment = environment.getSystemEnvironment();
systemEnvironment.forEach((k,v)->{
System.out.println("env >>>>>>>>>>>>> k="+k + "v="+ v);
});
// 获取配置文件的变量
System.out.println(environment.getProperty("server.port"));
// --- 事件
public class MyEvent extends ApplicationEvent implements Serializable {
public MyEvent(Object source) {
super(source);
}
}
// --- 监听器
@Component
public class EVListener {
@EventListener
public void recv(MyEvent e) {
System.out.println(("接受到事件: source=" + e.getSource() + "time=" + e.getTimestamp()));
}
}
// --- 发布事件
ConfigurableApplicationContext context = SpringApplication.run(ShowBeanApplication.class, args);
context.publishEvent(new MyEvent(context));
容器的实现
BeanFactory
的实现
ApplicationContext
的实现
xml
配置
:::info
怎么通过 xml
配置 bean
:::
public class ApplicationContextTest {
public static void main(String[] args) {
testClassPathXmlApplicationContext();
testFileSystemXmlApplicationContext();
}
/**
* 最为经典 基于 classpath 下的xml配置文件来创建
*/
private static void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml");
System.out.println(context.getBean(Bean2.class).getBean1());
}
/**
* 基于磁盘路径的 xml 配置文件来创建
*/
private static void testFileSystemXmlApplicationContext() {
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("//Users/csjerry/project/java/easy_spring_mvc/learn_spring/show_bean/src/test/resources/b01.xml");
System.out.println(context.getBean(Bean2.class).getBean1());
}
public static class Bean1 {
Bean1() {
System.out.println(">>>>>>>>>> 1");
}
}
public static class Bean2 {
private Bean1 bean1;
public Bean2() {
System.out.println(">>>>>>>>>>>> 2.");
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
}
<?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="bean1" class="com.example.show_bean.ApplicationContextTest.Bean1"/>
<bean id="bean2" class="com.example.show_bean.ApplicationContextTest.Bean2">
<property name="bean1" ref="bean1"/>
</bean>
</beans>
xml
创建bean
的原理通过
XmlBeanDefinitionReader
的loadBeanDefinitions
实现。
public static void main(String[] args) {
// xml 读取的原理
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println(">>>>>>>> 读取钱前");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(">>>>>>> 读取后");
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
int i = reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
// int i = reader.loadBeanDefinitions(new FileSystemResource("//Users/csjerry/project/java/easy_spring_mvc/learn_spring/show_bean/src/test/resources/b01.xml"));
System.out.println(">>>>>>>>>> 读取" + i + "bean");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
配置类配置
普通 bean
public class ApplicationContextTest {
testAnnotationConfigApplicationContext();
}
/**
* java 配置类来创建
*/
private static void testAnnotationConfigApplicationContext() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
System.out.println(context.getBean(Bean2.class).getBean1());
}
@Configuration
public static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2(Bean1 bean1) {
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
public static class Bean1 {
Bean1() {
System.out.println(">>>>>>>>>> 1");
}
}
public static class Bean2 {
private Bean1 bean1;
public Bean2() {
System.out.println(">>>>>>>>>>>> 2.");
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
}
用于 web 环境 (用错类debug了半天,差点怀疑人生)
public class AnnotationConfigServletWebContext {
public static void main(String[] args) {
// public class AnnotationConfigServletWebServerApplicationContext
// extends ServletWebServerApplicationContext
// implements AnnotationConfigRegistry
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
// AnnotationConfigServletWebApplicationContext
// extends GenericWebApplicationContext
// implements AnnotationConfigRegistry
// 注意这个类不会启动 tomcat
// AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext(WebConfig.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(">>>>>>>>>>>name="+name);
}
//
}
static class WebConfig {
// 内嵌 tomcat
@Bean
public ServletWebServerFactory servletWebServerFactory () {
System.out.println(">>>>>>> tomcat");
return new TomcatServletWebServerFactory();
}
// 路径派发
@Bean
public DispatcherServlet dispatcherServlet() {
System.out.println(">>>>>>>> dispatch");
return new DispatcherServlet();
}
// 注册 dispatch 到 tomcat
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
System.out.println(">>>>>>>>registrationBean");
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
// 使用的是 org.springframework.web.servlet.mvc.Controller
@Bean("/hello")
public Controller controller1() {
System.out.println(">>>>>>>> controller");
return ((request, response) -> {
response.getWriter().println("hello");
return null;
});
}
}
}
Bean 的生命周期
实例化 -> 依赖注入 -> 销毁
用到模版方法 的设计模式
3.1 Bean 的常见的后处理器
测试代码
GenericApplicationContext
直接继承AbstractApplicationContext
是一个干净的容器。
@Slf4j
@ToString
public class Bean1 {
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.info("@Autowired 生效: {}", bean2);
this.bean2 = bean2;
}
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.info("@Resource 生效: {}", bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME:hello world'}") String home) {
log.info("@Value 生效: {}", home);
this.home = home;
}
@PostConstruct
public void init() {
log.info("@PostConstruct 生效");
}
@PreDestroy
public void destroy() {
log.info("@PreDestroy 生效");
}
}
//-
package com.example.show_bean.a04;
public class Bean2 {
}
//-
package com.example.show_bean.a04;
public class Bean3 {
}
//-
package com.example.show_bean.a04;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Getter
@Setter
@ToString
@ConfigurationProperties(prefix = "java")
public class Bean4 {
private String home;
private String version;
}
package com.example.show_bean.a04;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.support.GenericApplicationContext;
public class A04Application {
public static void main(String[] args) {
// GenericApplicationContext 是一个干净的容器
GenericApplicationContext context = new GenericApplicationContext();
// // 解析值注入内容
// context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
//
// // @Autowired @Value
// context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
//
// // @Resource @PostConstruct @PreDestroy
// context.registerBean(CommonAnnotationBeanPostProcessor.class);
//
// // @ConfigurationProperties 获取环境变量信息
// ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
// 用原始方式注册三个 bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4", Bean4.class);
// 初始化容器。执行 beanFactory 后置处理器,添加 bean 后置处理器,初始化所有单例
context.refresh();
System.out.println(context.getBean(Bean4.class));
// 销毁容器
context.close();
}
}
此时,启动类运行,只会打印基础的信息
接下来,一步一步地打开后处理器的注释,查看处理器的作用
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
:::info
注册 getDefaultListableBeanFactory
处理器后,可以拿到系统的环境变量信息。
:::
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
:::info
注册 AutowiredAnnotationBeanPostProcessor
之后, autowired
生效, 但是值注入失败。
:::
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
:::info
替换完 setAutowireCandidateResolver
之后,值注入成功
:::
context.registerBean(CommonAnnotationBeanPostProcessor.class);
:::info
注册 CommonAnnotationBeanPostProcessor
之后, @Resource @PostConstruct @PreDestroy
生效。
:::
总结
:::warning
通过前文可知
AutowiredAnnotationBeanPostProcessor
用于解析@Autowired 和 @Value
注解。CommonAnnotationBeanPostProcessor
解析@Resource @PostConstruct @PreDestroy
getDefaultListableBeanFactory
获取系统环境变量setAutowireCandidateResolver
配合AutowiredAnnotationBeanPostProcessor
进行值注入。
:::
3.2 工厂后处理器的模拟实现
:::warning
涉及后处理器 @ComponentScan, @Bean
:::
@Slf4j
public class A05Application {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
ComponentScan scan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
if(scan != null) {
String[] strings = scan.basePackages();
for (String s : strings) {
System.out.println(">>>>> prev->: " + s);
//-> classpath*:com/example/show_bean/**/*.class
s = "classpath*:"+s.replace(".", "/") + "/**/*.class";
System.out.println(">>>>> post->: " + s);
Resource[] resources = context.getResources(s);
for (Resource resource : resources) {
MetadataReader metadataReader = cachingMetadataReaderFactory.getMetadataReader(resource);
String className = metadataReader.getClassMetadata().getClassName();
System.out.println("类名:" + className);
boolean b = metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName());
System.out.println("是否加了 @Component: " + b);
boolean b1 = metadataReader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName());
System.out.println("是否加了 @Component 派生注解: " + b1);
}
}
}
context.refresh();
}
}
//- Config
@Component
@ComponentScan(basePackages = "com.example.show_bean.a05.component")
public class Config {
public Config() {
System.out.println(">>>>>>>> config init");
}
}
//- bean2
@Component
public class bean2 {
public bean2(){
System.out.println(">>>>>>>>>" + bean2.class.getSimpleName() + "spring init");
}
}
//- bean3
@Controller
public class bean3 {
public bean3(){
System.out.println(">>>>>>>>>" + bean3.class.getSimpleName() + "spring inti ");
}
}
//- bean4
public class bean4 {
public bean4(){
System.out.println(">>>>>>>>>" + bean4.class.getSimpleName() + "init");
}
}
运行结果
:::warning
修改 Application 代码使之扫描组件注册成 bean
:::
package com.example.show_bean.a05;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
public class A05Application {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
ComponentScan scan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
// 根据注解生成 bean 名字
AnnotationBeanNameGenerator annotationBeanNameGenerator = new AnnotationBeanNameGenerator();
DefaultListableBeanFactory defaultListableBeanFactory = context.getDefaultListableBeanFactory();
if(scan != null) {
String[] strings = scan.basePackages();
for (String s : strings) {
System.out.println(">>>>> prev->: " + s);
//-> classpath*:com/example/show_bean/**/*.class
s = "classpath*:"+s.replace(".", "/") + "/**/*.class";
System.out.println(">>>>> post->: " + s);
Resource[] resources = context.getResources(s);
for (Resource resource : resources) {
MetadataReader metadataReader = cachingMetadataReaderFactory.getMetadataReader(resource);
String className = metadataReader.getClassMetadata().getClassName();
// System.out.println("类名:" + className);
boolean b = metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName());
// System.out.println("是否加了 @Component: " + b);
boolean b1 = metadataReader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName());
// System.out.println("是否加了 @Component 派生注解: " + b1);
if(b || b1) {
// 加了 @Component 以及派生注解的 转换成 bean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(className)
.getBeanDefinition();
String beanName = annotationBeanNameGenerator.generateBeanName(beanDefinition, defaultListableBeanFactory);
defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
for (String name : context.getBeanDefinitionNames()) {
System.out.println(">>>>>>>>>beanName="+name);
}
}
}
context.refresh();
}
}
运行 bean2, bean3
注册成功, bean4
没有注册,符合预期。
:::warning
将 bean
注册部分代码,抽取成一个后处理器, 修改启动类以及新添加后处理器类。
后处理器需要实现 BeanFactoryPostProcessor
, 他会在 调用 refresh
时执行。
:::
@Slf4j
public class A05Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// 注册后处理器
context.registerBean(ComponentScanPostProcessor.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(">>>>>>>>>beanName="+name);
}
}
}
//-
public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try {
ComponentScan scan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
// 根据注解生成 bean 名字
AnnotationBeanNameGenerator annotationBeanNameGenerator = new AnnotationBeanNameGenerator();
// 获取资源文件
PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
if (scan != null) {
String[] strings = scan.basePackages();
for (String s : strings) {
System.out.println(">>>>> prev->: " + s);
//-> classpath*:com/example/show_bean/**/*.class
s = "classpath*:" + s.replace(".", "/") + "/**/*.class";
System.out.println(">>>>> post->: " + s);
Resource[] resources = patternResolver.getResources(s);
for (Resource resource : resources) {
MetadataReader metadataReader = cachingMetadataReaderFactory.getMetadataReader(resource);
String className = metadataReader.getClassMetadata().getClassName();
// System.out.println("类名:" + className);
boolean b = metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName());
// System.out.println("是否加了 @Component: " + b);
boolean b1 = metadataReader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName());
// System.out.println("是否加了 @Component 派生注解: " + b1);
if (b || b1) {
// 加了 @Component 以及派生注解的 转换成 bean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(className)
.getBeanDefinition();
if (configurableListableBeanFactory instanceof DefaultListableBeanFactory defaultListableBeanFactory) {
String beanName = annotationBeanNameGenerator.generateBeanName(beanDefinition, defaultListableBeanFactory);
defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
}
} catch (Exception e) {
throw new RuntimeException("注册 bean 失败" + e.getMessage());
}
}
}
:::warning
@Bean
:::
package com.example.show_bean.a05;
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.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.Set;
public class BeanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
try {
CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
MetadataReader reader = cachingMetadataReaderFactory.getMetadataReader(new ClassPathResource("com/example/show_bean/a05/Config.class"));
Set<MethodMetadata> annotatedMethods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata method : annotatedMethods) {
String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
definitionBuilder.setFactoryMethodOnBean(method.getMethodName(), "config");
// 设置注入模式
definitionBuilder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
if(StringUtils.hasLength(initMethod)) {
definitionBuilder.setInitMethodName(initMethod);
}
AbstractBeanDefinition bd = definitionBuilder.getBeanDefinition();
if(configurableListableBeanFactory instanceof DefaultListableBeanFactory defaultListableBeanFactory) {
defaultListableBeanFactory.registerBeanDefinition(method.getMethodName(), bd);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
:::warning
@Mapper
:::
@Mapper
public interface Mapper1 {
}
//-
@Mapper
public interface Mapper2 {
}
//- MapperFactoryBean 注册
@Bean
public MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory) {
MapperFactoryBean<Mapper1> factoryBean = new MapperFactoryBean<>(Mapper1.class);
factoryBean.setSqlSessionFactory(sqlSessionFactory);
return factoryBean;
}
@Bean
public MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory) {
MapperFactoryBean<Mapper2> factoryBean = new MapperFactoryBean<>(Mapper2.class);
factoryBean.setSqlSessionFactory(sqlSessionFactory);
return factoryBean;
}
MapperFactoryBean
只能注册一个 bean
, 抽象成一个后处理器进行扫描 批量 注册
package com.example.show_bean.a05;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.lang.NonNull;
public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(@NonNull BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/example/show_bean/a05/mapper/**/*.class");
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
AnnotationBeanNameGenerator nameGenerator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
ClassMetadata classMetadata = reader.getClassMetadata();
if (classMetadata.isInterface() && reader.getAnnotationMetadata().hasAnnotation(Mapper.class.getName())) {
// 是接口且有@Mapper
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
.addConstructorArgValue(classMetadata.getClassName())
// 按照类型注入 SqlSessionFactory
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
// 生成一个新的 beanDefinitional 生成一个 beanName
AbstractBeanDefinition beanDefinition1 = BeanDefinitionBuilder
.genericBeanDefinition(classMetadata.getClassName())
.getBeanDefinition();
String beanName = nameGenerator.generateBeanName(beanDefinition1, beanDefinitionRegistry);
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}
}
}catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
@Override
public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
3.3 Aware
接口以及 InitializingBean
Aware 接口用于注入一些与容器相关的信息,例如
BeanNameAware
注入Bean
的名字BeanFactoryAware
注入BeanFactory
容器ApplicationContextAware
注入ApplicationContext
容器EmbeddedResolverAware
注入${}
public class A06Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myBean", MyBean.class);
context.refresh();
context.close();
}
}
//-
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
@Override
public void setBeanName(String s) {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " 名字叫:" + s);
}
@Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " applicationContext 容器是:" + applicationContext);
}
@Override
public void afterPropertiesSet() {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " InitializingBean");
}
}
运行结果
BeanFactoryAware
注入BeanFactory
容器、ApplicationContextAware
注入ApplicationContext
容器、EmbeddedResolverAware
注入${}
使用@Autowired
就能实现,为什么还要用Aware
接口呢?
@Autowire
的解析需要 bean 后处理器,属于扩展功能,而Aware
接口属于内置功能,不需要任何扩展,Spring
就能识别。
某种情况下,扩展功能会失效,而内置功能不会。
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
@Override
public void setBeanName(String s) {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " 名字叫:" + s);
}
@Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " applicationContext 容器是:" + applicationContext);
}
@Override
public void afterPropertiesSet() {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " InitializingBean");
}
@Autowired
public void set(ApplicationContext applicationContext) {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " @Autowired 注入的 applicationContext 容器是:" + applicationContext);
}
@PostConstruct
public void init() {
System.out.println("setBeanName" + this.getClass().getSimpleName() + " @PostConstruct InitializingBean");
}
}
如果只是简单地添加 Autowired,@PostConstruct
在,空容器环境下并不会执行。需要添加相应的后处理器。
public class A06Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myBean", MyBean.class);
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.refresh();
context.close();
}
}
Autowired,@PostConstruct
正常执行以及注入。
3.4 AutoWired 以及 PostConstruct 失效的情况分析
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myconfig", MyConfig1.class);
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.refresh();
context.close();
}
//-
@Slf4j
@Configuration
public class MyConfig1 {
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
log.info("注入 ApplicationContext");
}
@PostConstruct
public void init() {
log.info("初始化");
}
}
运行之后正常打印。但是加入以下代码之后运行 Autowired , PostConstruct
失效。
在 Config1 中添加了一个被 @Bean 注解标记的 processor1() 方法,用于向容器中添加 BeanFactoryPostProcessor。processor1() 方法成功生效,但 @Autowired 和 @PostConstruct 注解的解析失败了。
@Slf4j
@Configuration
public class MyConfig1 {
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
log.info("注入 ApplicationContext");
}
@PostConstruct
public void init() {
log.info("初始化");
}
@Bean
public BeanFactoryPostProcessor processor1() {
return processor -> log.info("执行 processor1");
}
}
对于
context.refresh()
方法来说,它主要按照以下顺序干了三件事:
- 执行
BeanFactory
后置处理器;- 添加
Bean
后置处理器;- 创建和初始化单例对象。
比如当 Java 配置类不包括 BeanFactoryPostProcessor
时:
BeanFactoryPostProcessor
会在 Java 配置类初始化之前执行。
当 Java 配置类中定义了 BeanFactoryPostProcessor
时,如果要创建配置类中的 BeanFactoryPostProcessor
就必须提前创建和初始化 Java 配置类。
在创建和初始化 Java 配置类时,由于 BeanPostProcessor
还未准备好,无法解析配置类中的 @Autowired
等注解,导致 @Autowired
等注解失效:
如果是实现接口,则正常打印
@Slf4j
@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
log.info("注入 ApplicationContext");
}
@Bean
public BeanFactoryPostProcessor processor1() {
return processor -> log.info("执行 processor1");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("初始化");
}
}