是根据黑马Spring源码课程总结的
首先使用SpringBoot来启动,java8即可,添加Spring的基本功能即可,如果需要后面可以继续加。
第二讲、容器实现
1、BeanFactory的实现
初始代码:
public class TestBeanFactory {
public static void main(String[] args) {
}
@Configuration
static class Config{
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
interface Inter{
}
static class Bean3 implements Inter{
}
static class Bean4 implements Inter{
}
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;
}
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
}
它用到了DefaultListableBeanFactory这个BeanFactory的实现类,而它也是最最核心的BeanFactory的实现类,现在可以定义bean并且创建bean,代码如下:
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//设置bean的定义,就如同xml文件设置bean一样,现在还不是创建bean的对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();
//使用beanFactory创建bean
beanFactory.registerBeanDefinition("config",beanDefinition);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
但是会发现,只有一个结果:
config
这是因为@Bean、@Autowired、@Resource等注解的功能还没加入,因为BeanFactory的功能没有其他的多。
如何添加注解的功能呢?
可以使用以下代码,给BeanFactory添加一些后置处理器,也就是一些新的功能:
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
这样还不够,后置处理器功能还没生效呢。但是可以在console中看出来,已经有一些后置处理器被加了进来:
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
接下来就是让它们执行其相应功能的逻辑,遍历beanFactory中的所有bean,然后获取类型是BeanFactoryPostProcessor的,让它们执行后置处理器:
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(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
bean1
bean2
也就是@Bean注解声明的对象也被加入到了beanFactory容器中了。
下面试着获取一下Bean1这个对象的Bean2参数,看看@Autowired注解是否把Bean2给引入进来了。
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
结果发现并没有:
[main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
null
也就是说上面的后处理器并没有把@Autowired和@Resource等注解的功能加进去,上面的那些后置处理器是BeanFactory级别的,还有一些是Bean级别的。(通过上面的getBeansOfType()可以选择是哪种类型的后置处理器),这些是针对Bean生命周期各个阶段的扩展。
那么怎么扩展BeanPostProcessor呢?
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//设置bean的定义,就如同xml文件设置bean一样,现在还不是创建bean的对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();
//使用beanFactory创建bean
beanFactory.registerBeanDefinition("config",beanDefinition);
//给BeanFactory添加一些后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
System.out.println("----------");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
}
这回看结果可以发现:
[main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
[main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean2 - 构造 Bean2()
com.oliver.spring_source.a02.TestBeanFactory$Bean2@35083305
查看各个bean是否为懒加载?
在getBean2()前打印一个分割行,看看构造方法是否是在分割行后面才执行?发现确实是,说明是懒加载。
------------------------------
16:06:19.685 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
16:06:19.687 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
16:06:19.701 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
16:06:19.711 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
16:06:19.711 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean2 - 构造 Bean2()
com.oliver.spring_source.a02.TestBeanFactory$Bean2@35083305
创建对象的时机可以提前吗?
可以的,使用beanFactory.preInstantiateSingletons();来提前加载:
16:07:58.735 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
16:07:58.750 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
16:07:58.763 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
16:07:58.764 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean2 - 构造 Bean2()
------------------------------
com.oliver.spring_source.a02.TestBeanFactory$Bean2@20d3d15a
2、后置处理器的排序
可以通过查看源码,看看这些注解是怎么加载进来的,看AnnotationConfigUtils类:
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
Autowired就是@Autowired注解,Common就是@Resource注解。
如果在某个对象上既加了@Autowired,又加了@Resource注解,那么哪个先生效呢?
先重新设置一下源代码:
public class TestBeanFactory {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//设置bean的定义,就如同xml文件设置bean一样,现在还不是创建bean的对象
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton").getBeanDefinition();
//使用beanFactory创建bean
beanFactory.registerBeanDefinition("config",beanDefinition);
//给BeanFactory添加一些后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
System.out.println(beanFactory.getBean(Bean1.class).getInter());
}
@Configuration
static class Config{
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
@Bean
public Bean3 bean3(){
return new Bean3();
}
@Bean
public Bean4 bean4(){
return new Bean4();
}
}
interface Inter{
}
static class Bean3 implements Inter{
}
static class Bean4 implements Inter{
}
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;
}
private Inter inter;
public Inter getInter(){
return inter;
}
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
}
这样还是按照原来的方式,把Bean1类的Inter属性加上@Autowired注解。然后还是获取bean1,发现报错:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.oliver.spring_source.a02.TestBeanFactory$Inter' available: expected single matching bean but found 2: bean3,bean4
也就是说@Autowired发现了两个Inter类型的bean对象,不知道应该放哪个。可以把Bean1的Inter参数名设置为bean3,这样在参数类型发现多个的时候可以按照对象名注入。
@Autowired
private Inter bean3;
public Inter getInter(){
return bean3;
}
也可以使用@Qualifier("bean3")。
再试试@Resource注解,把名称还改成inter。还是报同样的错。
但是可以设置bean的名字,根据这个名字去找,而不是参数名找,下面这个例子找到的是Bean3的对象,而不是Bean4的对象。
@Resource(name = "bean3")
private Inter bean4;
public Inter getInter(){
return bean4;
}
这个时候加两个注解怎么办?哪个生效?
@Autowired
@Resource(name = "bean3")
private Inter bean4;
public Inter getInter(){
return bean4;
}
如果按照上面这个,最终如果是bean4被注入,说明@Autowired被注入,如果是bean3被注入说明@Resource起了作用。最后发现是bean4起了作用。
16:34:46.922 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean4'
其实是后处理器哪个先添加进beanFactory容器,哪个先生效,可以打印看一下:
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
System.out.println(beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
打印结果如下:
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@3f200884
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@4d339552
可以看出是Autowired先添加进来。
那么可以改顺序吗?
当然可以,可以通过比较器对象来设置。
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor -> {
System.out.println(beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
变成上面这样可以通过结果看出,加载顺序确实变了:
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@4d339552
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@f0f2775
查看一下源码
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
在registerAnnotationConfigProcessors()中的setDependencyComparator设置了比较器。
顺序也可以看一下:AutowiredAnnotationBeanPostProcessor类中顺序,使用setOrder()设置:
private int order = Ordered.LOWEST_PRECEDENCE - 2;
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
而CommonAnnotationBeanPostProcessor类是这样设置的:
public CommonAnnotationBeanPostProcessor() {
this.setOrder(Ordered.LOWEST.PRECEDENCE - 3);
this.setInitAnnotationType(PostConstruct.class);
this.setDestroyAnnotationType(PreDestroy.class);
this.ignoreResourceType("javax.xml.ws.WebServiceContext");
}
因为Common这个注解 - 3,而Autowired注解 - 2,也就是Common注解优先级更高。
3、ApplicationContext的实现
ApplicationContext比BeanFactory多了很多功能,首先可以使用不同的方式创建容器,获取bean实例。
先看最基础的代码:
public class A02 {
private static final Logger log = LoggerFactory.getLogger(A02.class);
public static void main(String[] args) {
testClassPathXmlApplicationContext();
testFileSystemXmlApplicationContext();
testAnnotationConfigApplicationContext();
testAnnotationConfigServletWebServerApplicationContext();
}
private static void testClassPathXmlApplicationContext() {
}
private static void testFileSystemXmlApplicationContext(){
}
private static void testAnnotationConfigApplicationContext() {
}
private static void testAnnotationConfigServletWebServerApplicationContext() {
}
@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;
};
}
}
@Configuration
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;
}
}
static class Bean1 {
}
static class Bean2 {
private Bean1 bean1;
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
}
- ClassPathXmlApplicationContext的代码
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());
}
- FileSystemXmlApplicationContext的代码
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());
}
- AnnotationConfigApplicationContext的代码
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());
}
BeanFactory又是怎样读取文件的呢?
private static void testBeanFactory(){
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取之前...");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("a02.xml");
System.out.println("读取之后...");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
通过XmlBeanDefinitionReader读取资源文件,然后使用reader.loadBeanDefinitions("a02.xml")加载bean定义。