BeanFactory实现:
1.创建Config类
java
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
2.创建Bean1类:
java
static class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
}
3.创建Bean2:
java
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
4.主类中创建BeanFactory的具体实现类:
java
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
5.定义Bean:
java
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
6.注册BeanDefinition:
java
beanFactory.registerBeanDefinition("config", beanDefinition);
7.验证BeanFactory中有哪些BeanDefinition:
java
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
发现:工厂中只有名字为config的Bean,该类中注解并未进行解析并注册!
添加处理器,对注解进行解析:
java
// 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
加了之后输出结果:
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor处理Configuration注解
org.springframework.context.annotation.internalAutowiredAnnotationProcessor处理Autowired注解
org.springframework.context.annotation.internalCommonAnnotationProcessor解析Resource注解
org.springframework.context.event.internalEventListenerProcessororg.springframework.context.event.internalEventListenerFactory
发现多了5个BeanDefinition,当然这5个的作用就是充当DeanFactory与Bean的后置处理器:
注:DeanFactory与Bean的后置处理器作用域是不同的!!!!
发现注解还是未被解析:
此时需要将BeanFactory后处理器(BeanFactoryPostProcessor)全部拿出来,然后按照添加到BeanFactory中的后处理器执行:
java
// BeanFactory 后处理器主要功能,补充了一些 bean 定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
此时发现被Bean注解标记的Bean1与Bean2被注册进BeanFactory!!
此时测试BeanDefinition是否被注册完整,由于Bean1中Autowired了Bean2,想通过Bean1将Bean2拿出来,测试代码如下:
java
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
结果为:null
此时Autowired并未被解析处理
此时需要让Bean的后处理器发挥作用,同理代码如下:
java
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values()
.forEach(beanFactory::addBeanPostProcessor);
此时运行代码,输出正常!!
此时通过输出结果可知,Bean的实例化、初始化的时机是第一次调用到对应的Bean方法时才会创建!
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2
bean3
bean4
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DEBUG\] 12:41:24.422 \[main\] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1() \[DEBUG\] 12:41:24.441 \[main\] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2() com.itheima.a02.TestBeanFactory$Bean2@76b1e9b8
希望对于单例对象,在注册Bean对象时就进行真正的对象创建初始化:
java
beanFactory.preInstantiateSingletons(); // 准备好所有单例
总结:
beanFactory 不会做的事 1. 不会主动调用 BeanFactory 后处理器 2. 不会主动添加 Bean 后处理器 3. 不会主动初始化单例 4. 不会解析beanFactory 还不会解析 ${ } 与 #{ } bean 后处理器会有排序的逻辑缺少很多的拓展功能!!
Autowired与Resource的生效顺序:
如果在自己的项目中,对于一个类的依赖注入既使用了Autowired又使用了Resource究竟那个先生效??
java
interface Inter {
}
static class Bean3 implements Inter {
}
static class Bean4 implements Inter {
}
java
static class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
@Autowired
@Resource(name = "bean4")
private Inter bean3;
public Inter getInter() {
return bean3;
}
}
测试:
java
System.out.println(beanFactory.getBean(Bean1.class).getInter());
输出结果:
TestBeanFactory$Bean3@74d1dc36
此时通过测试发现,注入的是Bean3,Resource注入并没有生效!!
应该是与BeanPostProcessor中Bean的顺序有关:
java
beanFactory.getBeansOfType(BeanPostProcessor.class).values()
.forEach(beanPostProcessor->{
System.out.println(">>>>"+beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
结果如下:
>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@c88a337
>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@5d0a1059
可以通过比较器对顺序进行控制:
java
beanFactory.getBeansOfType(BeanPostProcessor.class).values()
.stream().sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor->{
System.out.println(">>>>"+beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@54bff557
>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@593aaf41
此时再次执行
java
System.out.println(beanFactory.getBean(Bean1.class).getInter());
结果如下:
com.itheima.a02.TestBeanFactory$Bean4@7161d8d1
排序是根据Comparator进行排序,各自的各小在构造函数时已经设置:
java
//数字越大优先级越高
public class AutowiredAnnotationBeanPostProcessor{
private int order = 2147483645;
}
public CommonAnnotationBeanPostProcessor() {
this.setOrder(2147483644);
}
ApplicationContext实现:
1.基于 classpath 下 xml 格式的配置文件来创建
java
<?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">
<!-- 控制反转, 让 bean1 被 Spring 容器管理 -->
<bean id="bean1" class="com.itheima.a02.A02.Bean1"/>
<!-- 控制反转, 让 bean2 被 Spring 容器管理 -->
<bean id="bean2" class="com.itheima.a02.A02.Bean2">
<!-- 依赖注入, 建立与 bean1 的依赖关系 -->
<property name="bean1" ref="bean1"/>
</bean>
</beans>
java
private static void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
用代码模仿整个Bean创建过程:
java
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取之前...");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("读取之后...");
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\a02.xml"));
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
2.️基于磁盘路径下 xml 格式的配置文件来创建
java
private static void testFileSystemXmlApplicationContext() {
FileSystemXmlApplicationContext context =
new FileSystemXmlApplicationContext(
"src\\main\\resources\\a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
3.️较为经典的容器, 基于 java 配置类来创建
java
private static void testAnnotationConfigApplicationContext() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
4.基于 java 配置类来创建, 用于 web 环境
1.创建Web环境:
java
@Configuration
static class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
2.调用并注册Bean
java
private static void testAnnotationConfigServletWebServerApplicationContext() {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}