目录
BeanFactory与ApplicationContext
BeanFactory
ApplicationContext
容器实现
BeanFactory实现
ApplicationContext实现
ClassPathXmlApplicationContext的实现
AnnotationConfigApplicationContext的实现
AnnotationConfigServletWebServerApplicationContext的实现
BeanFactory与ApplicationContext
BeanFactory
BeanFactory是ApplicationContext的父接口。是Spring的核心容器,ApplicationContext的主要的方法均是调用BeanFactory的方法。比如说下面获取bean对象案例中
@SpringBootApplication
public class CodeApplication {public static void main(String[] args) {ConfigurableApplicationContext ctx = SpringApplication.run(CodeApplication.class, args);ctx.getBean("abc");}
}
通过Ctrl+alt+b键可以看到具体的实现方法如下,先获取BeanFactory对象后调用BeanFactory对象的getBean()方法。
@Overridepublic Object getBean(String name) throws BeansException {assertBeanFactoryActive();return getBeanFactory().getBean(name);}
BeanFactory表面只能getBean(),实际上控制反转,基本的依赖注入、直至Bean的生命周期的各种功能,都由它的实现类体提供。
ApplicationContext
相比较BeanFactory,ApplicationContext多了哪些功能?
由类图可以看出,ApplicationContext除了继承BeanFactory的两个接口,也继承了四个其他接口。
接下来分别用代码查看具体做了什么。
首先是翻译。不过该翻译需要自己导入文本
首先在resource包下创建messages开头的properties文件。在里面编写key=value样式的翻译
在主程序中编写代码。可以正常输出翻译后的内容。
第二个就是路径查找资源
第三个是从环境中获取配置值
第四个是发布事件
这个可以用于解耦,比如用户注册成功后,可能需要发送短信通知,又或是邮件通知。不知道如何去通知时,不能随意更改注册部分的功能,这时可以通过发布事件来处理。
首先自定义事件,需要继承ApplicationEvent类。
//自定义事件,需要继承ApplicationEvent
public class UserRegisterEvent extends ApplicationEvent {public UserRegisterEvent(Object source) {super(source);}
}
@Component
public class Component1 {@Autowiredprivate ApplicationEventPublisher publisher;public void register(){System.out.println("用户注册");//发布者发布一个UserRegisterEvent事件,从this这个对象发出publisher.publishEvent(new UserRegisterEvent(this));}
}
@Component
public class Component2 {@EventListenerpublic void send(UserRegisterEvent event){System.out.println("发送信息"+event);}
}
@SpringBootApplication
public class CodeApplication {public static void main(String[] args) {ConfigurableApplicationContext ctx = SpringApplication.run(CodeApplication.class, args);Component1 publisher = ctx.getBean(Component1.class);publisher.register();}
}
运行结果如下
用户注册
发送信息com.zmt.test.UserRegisterEvent[source=com.zmt.test.Component1@1d3ac898]
容器实现
BeanFactory实现
从空项目中从头实现BeanFactory
public class TestBeanFactory {public static void main(String[] args) {/*** 从头实现BeanFactory*///创建bean工厂DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//beanDefinition定义,存储class,scope,初始化方法,销毁方法等信息AbstractBeanDefinition bean = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();beanFactory.registerBeanDefinition("config",bean);//接下来获取查看哪些bean被加载String[] names = beanFactory.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}}@Configurationstatic class Config {@Beanpublic Bean1 bean1(){return new Bean1();}@Beanpublic Bean2 bean2(){return new Bean2();}}static class Bean1 {@Autowiredprivate Bean2 bean2;public Bean1() {System.out.println("构造bean1");}public Bean2 getBean2() {return bean2;}}static class Bean2 {public Bean2() {System.out.println("构造bean2");}}
}
运行结果如下
config
由此可以看出,这些注解都没有被解析。只有初始时定义的bean被加载。想要解析注解,需要给beanFactory添加一个后处理器。
运行结果如下
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
可以看到添加了五个处理器。接下来调用这些处理器去解析注解
运行结果如下
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
这里看到,可以成功解析注解了,测试Bean1中的getBean2方法发现
bean2并没有被注入,很显然时@Autowried没有起作用。我们需要再写一个Bean后处理器(针对bean的生命周期各个阶段进行扩展)。
也从另一方面体现了,只有当只用bean对象时才会被创建,不使用时只会在beanFactory中保存bean信息。
如果需要提前加载bean,则需要调用方法beanFactory.preInstantiateSingletons()。
具体代码如下
public class TestBeanFactory {public static void main(String[] args) {/*** 从头实现BeanFactory*///创建bean工厂DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//beanDefinition定义,存储class,scope,初始化方法,销毁方法等信息AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();//将beanDefinition注册到beanFactory中beanFactory.registerBeanDefinition("config", beanDefinition);//为BeanFactory添加一些常用的Bean工厂后处理器AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);//调用bean工厂后处理器的方法beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(processor -> processor.postProcessBeanFactory(beanFactory));for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}//将BeanDefinition中的Bean后处理器添加bean后处理器beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);//单例对象事先创建,而不是创建时才创建bean对象beanFactory.preInstantiateSingletons();System.out.println(beanFactory.getBean(Bean1.class).getBean2());}@Configurationstatic class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2() {return new Bean2();}}static class Bean1 {@Autowiredprivate Bean2 bean2;public Bean1() {System.out.println("构造bean1");}public Bean2 getBean2() {return bean2;}}static class Bean2 {public Bean2() {System.out.println("构造bean2");}}
}
从上述代码中我们可以得到以下结论
- beanFactory不会主动调用Bean工厂后处理器
- beanFactory不会主动添加Bean后处理器
- beanFactory不会主动初始化单例bean
- beanFactory不会解析${}与#{}
ApplicationContext实现
ClassPathXmlApplicationContext的实现
<?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.zmt.test3.Bean1"/><bean id="bean2" class="com.zmt.test3.Bean2"><property name="bean1" ref="bean1"/></bean>
</beans>
public static void testClassPathXmlApplication(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}System.out.println(context.getBean(Bean2.class).getBean1());
}
运行结果如下
bean1
bean2
com.zmt.test3.Bean1@5f3a4b84
applicationContext读取xml中的配置具体操作如下
public static void main(String[] args){//创建BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//创建xml读取器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);System.out.println("读取配置文件前");for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}//读取xml文件reader.loadBeanDefinitions("application.xml");System.out.println("读取配置文件后");for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}
}
运行结果如下
读取配置文件前
20:52:54.539 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [application.xml]
读取配置文件后
bean1
bean2
读取xml文件的实现方式还有一种FileSystemXmlApplicationContext,这种实现方式与ClassPathXmlApplicationContext的区别在于前者可以指定配置文件在磁盘中的路径或是src下的路径,其他与后者无异。
AnnotationConfigApplicationContext的实现
@Configuration
public class Config{@Beanpublic Bean1 bean1(){return new Bean1();}//也可以通过添加@Autowired注解在Bean2中注入bean1对象@Beanpublic Bean2 bean2(Bean1 bean1){Bean2 bean2 = new Bean2();bean2.setBean1(bean1);return bean2;}
}
public static void testAnnotationConfigApplicationContext(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}System.out.println(context.getBean(Bean2.class).getBean1());
}
运行结果如下
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
codeApplication.Config
bean1
bean2
com.zmt.test3.Bean1@96def03
由此可以看出,相比于ClassPahtXmlApplicationContext中,AnnotationConfigApplicationContext会自动添加常用的后处理器并主动调用这些后处理器
AnnotationConfigServletWebServerApplicationContext的实现
这个是用于web环境下的容器实现,既支持Java配置类又支持servlet与servlet的web容器
public static void testAnnotationConfigServletWebServerApplicationContext(){AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}
}
@Configuration
public class WebConfig{//创建一个web容器@Beanpublic ServletWebServerFactory servletWebServerFactory(){return new TomcatServletWebServerFactory();}//前端控制器,用来分发Servlet@Beanpublic DispatcherServlet dispatcherServlet(){return new DispatcherServlet();}//将前端控制器注册到Web容器当中@Beanpublic DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){return new DispatcherServletRegistrationBean(dispatcherServlet,"/");}//创建一个控制器用来处理前端请求@Bean("/hello")//当Bean注解中以/开头时,后面的内容除了作为bean名称外,还要充当网络访问路径public Controller controller1(){return new Controller() {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {response.getWriter().print("hello");return null;}};}
}
运行结果如下
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
codeApplication.WebConfig
servletWebServerFactory
dispatcherServlet
registrationBean
/hello
访问/hello路径结果如下