【Java】Spring5学习
基础环境与文档资料:
见黑马视频:
https://www.bilibili.com/video/BV1P44y1N7QG
依赖坐标:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.cloud9</groupId>
<artifactId>Spring5</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
</project>
一、ApplicationContext接口
package cn.cloud9;
import cn.cloud9.bean.Component1;
import cn.cloud9.event.UserRegisteredEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
/**
* @projectName: Spring5
* @author: OnCloud9
* @date: 2023年02月07日 09:13
* @version: 1.0
*/
@Slf4j
@SpringBootApplication
public class MainApplication {
@SneakyThrows
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);
log.info("ConfigurableApplicationContext -> {}", applicationContext);
/*
* ApplicationContext的功能
* 1、I18N支持, MessageSource接口实现
* - 默认读取的配置文件:messages.properties
* - 指定文件文件名称 中文zh 英文en 日文ja
*/
String cnHello = applicationContext.getMessage("hello", null, Locale.CHINA);
String enHello = applicationContext.getMessage("hello", null, Locale.ENGLISH);
String jpHello = applicationContext.getMessage("hello", null, Locale.JAPANESE);
log.info("I18N 国际化参数读取 CN -> {}, EN -> {}, JP -> {}", cnHello, enHello, jpHello);
/*
* ApplicationContext的功能
* 2、读取类路径下的资源
* - classpath: * 读取当前项目下的类路径资源
* - classpath*: * 读取项目所有依赖下的类路径
*/
Resource[] resources = applicationContext.getResources("classpath:*");
Arrays.stream(resources).forEach(resource -> log.info("classpath: -> {}", resource));
resources = applicationContext.getResources("classpath*:*");
Arrays.stream(resources).forEach(resource -> log.info("classpath*: -> {}", resource));
// 获取Spring的SPI配置文件
resources = applicationContext.getResources("classpath*:META-INF/spring.factories");
Arrays.stream(resources).forEach(resource -> log.info("META-INF/spring.factories: -> {}", resource));
/*
* ApplicationContext的功能
* 3、读取配置文件的值
*/
ConfigurableEnvironment environment = applicationContext.getEnvironment(); // 系统变量 + 配置文件
String javaHome = environment.getProperty("java_home");
String serverPort = environment.getProperty("server.port");
log.info("javaHome -> {}, serverPort -> {}", javaHome, serverPort);
/*
* ApplicationContext的功能
* 4、发布事件
* - 发布事件的意义是为了解耦业务逻辑
*/
// 1、使用ApplicationContext直接发布事件
UserRegisteredEvent userRegisteredEvent = new UserRegisteredEvent(applicationContext);
applicationContext.publishEvent(userRegisteredEvent);
// 2、使用Bean对象发布事件
Component1 component1 = applicationContext.getBean("component1", Component1.class);
component1.registerBusinessAction();
}
}
I18N国际化配置文件:

UserRegisteredEvent事件源类:
package cn.cloud9.event;
import org.springframework.context.ApplicationEvent;
/**
* 用户注册事件类
* @author OnCloud9
* @version 1.0
* @project Spring5
* @date 2023年02月08日 10:45
*/
public class UserRegisteredEvent extends ApplicationEvent {
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public UserRegisteredEvent(Object source) {
super(source);
}
}
在Component2类的监听方法:
package cn.cloud9.bean;
import cn.cloud9.event.UserRegisteredEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* @projectName: Spring5
* @author: OnCloud9
* @date: 2023年02月07日 09:30
* @version: 1.0
*/
@Slf4j
@Component
public class Component2 {
/**
* @author OnCloud9
* @date 2023/2/8 11:01
* @description
* @params [event]
* @return void
*/
@EventListener
public void receiveEvent(UserRegisteredEvent event) {
log.info("用户注册事件触发, 监听方法执行!!!!");
}
}
Component1中的发布事件方法:
package cn.cloud9.bean;
import cn.cloud9.event.UserRegisteredEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @projectName: Spring5
* @author: OnCloud9
* @date: 2023年02月07日 09:30
* @version: 1.0
*/
@Slf4j
@Component
public class Component1 {
@Resource
private ApplicationEventPublisher applicationEventPublisher;
/**
* @author OnCloud9
* @date 2023/2/8 11:06
* @description 用户注册业务行为
* @params []
* @return void
*/
public void registerBusinessAction() {
log.info("用户注册业务行为开始!");
applicationEventPublisher.publishEvent(new UserRegisteredEvent(this));
}
}
启动时打印信息:
2023-02-08 14:36:50.523 INFO 6548 --- [ main] cn.cloud9.bean.Component2 : 用户注册事件触发, 监听方法执行!!!! 2023-02-08 14:36:50.524 INFO 6548 --- [ main] cn.cloud9.bean.Component1 : 用户注册业务行为开始! 2023-02-08 14:36:50.524 INFO 6548 --- [ main] cn.cloud9.bean.Component2 : 用户注册事件触发, 监听方法执行!!!!
二、BeanFactory接口
/*
* BeanFactory
* 1、是ApplicationContext的父接口
* 2、是Spring的核心容器
* 3、ApplicationContext组合了BeanFactory的功能
* 4、获取Bean对象,控制反转,依赖注入,Bean的生命周期的各种功能,由BeanFactory的实现类完成
*/
Field field = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
field.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
Map<String,Object> beanTanker = (Map<String,Object>)field.get(beanFactory);
beanTanker.entrySet().stream().filter(e -> e.getKey().startsWith("component")).forEach(e -> {
log.info("key -> {}, value -> {}", e.getKey(), e.getValue());
});
import cn.cloud9.MainApplication;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.Map;
/**
* @author OnCloud9
* @version 1.0
* @project Spring5
* @date 2023年02月08日 11:12
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MainApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BeanFactoryTest {
/**
* @author OnCloud9
* @date 2023/2/8 13:47
* BeanFactory
* - 不会主动调用BeanFactory的后置处理器
* - 不会主动调用Bean的后置处理器
* - 不会主动初始化单例Bean对象
* - 不会解析BeanFactory, 包括${} #{} 值注入
* Bean的后处理有排序逻辑
*
*/
@Test
public void beanInitializeProcess() {
/*
* Bean的定义, 初始化, scope, 销毁,
*/
final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
/* 1、生成Bean的定义对象 */
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
/* 2、Bean工厂注册定义对象 */
beanFactory.registerBeanDefinition("config", beanDefinition);
/* 3、获取注册的Bean定义名称集合 */
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) log.info("beanDefinitionName: {}", beanDefinitionName);
}
@Configuration
static class Config {
@org.springframework.context.annotation.Bean
public Bean1 bean1() {
return new Bean1();
}
@org.springframework.context.annotation.Bean
public Bean2 bean2() {
return new Bean2();
}
}
@Data
private static class Bean1 {
@Autowired
private Bean2 bean2;
}
private static class Bean2 {}
}
在注册Bean定义对象之后
beanFactory.registerBeanDefinition("config", beanDefinition);
BeanFactory对象中只有当前这个config的Bean定义对象
一些自动装配注解,事件监听需要后置处理器的加入:
/* 4、添加一些常用的后处理器 */
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
/*
* 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
*/
log.info("添加后置处理器后...");
beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) log.info("beanDefinitionName : {}", beanDefinitionName);
打印结果:
2023-02-08 14:54:26.964 INFO 33432 --- [ main] BeanFactoryTest : 添加后置处理器后... 2023-02-08 14:54:26.964 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: config 2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor 2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor 2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalCommonAnnotationProcessor 2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerProcessor 2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerFactory
但是我们发现Bean1和Bean2并没有在BeanFactory中注册
BeanFactory的后置处理器只是被添加到BeanFactory,并没有调用处理方法
所以需要把每个处理器的处理方法都调用一遍才行
/* 5、获取BeanFactory处理器的容器, 用于BeanFactory的后置处理器的添加 */
Map<String, BeanFactoryPostProcessor> processorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
processorMap.values().forEach(p -> {
/* 调用每个处理器的处理方法, 扩充Bean的定义 */
p.postProcessBeanFactory(beanFactory);
});
log.info("在后置处理器处理后..."); /* config下的 bean1 bean2 被注册进来 */
beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) log.info("beanDefinitionName: {}", beanDefinitionName);
再次打印之后发现,Bean1和Bean2加入进来了:
2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : 在后置处理器处理后... 2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: config 2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor 2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor 2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalCommonAnnotationProcessor 2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerProcessor 2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerFactory 2023-02-08 14:54:26.973 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: bean1 2023-02-08 14:54:26.973 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: bean2
在Bean1中我们设置了Bean2成员属性,并且标注自动装配
然后在BeanFactory获取Bean1内的Bean2实例时,发现Bean2对象并没有注入:
/* 在没有扫描@Autowired注解驱动时不能装填Bean实例 */
log.info("打印bean2对象:{}", beanFactory.getBean(Bean1.class).getBean2());
打印结果:
2023-02-08 15:09:38.299 INFO 3852 --- [ main] BeanFactoryTest : 打印bean2对象:null
因为之前的处理只针对BeanFactory的后置处理,对于一个配置Bean来说
配置Bean中要注册的Bean并不归于BeanFactory的后置处理,而是Bean的后置处理
所以这里需要做Bean的后置处理:
/* 添加Bean的后置处理器 */
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
/* 在Bean的处理器添加之后,Bean2的对象装配了 */
log.info("打印bean2对象:{}", beanFactory.getBean(Bean1.class).getBean2());
打印结果:
2023-02-08 15:15:54.219 INFO 23160 --- [ main] BeanFactoryTest : 打印bean2对象:BeanFactoryTest$Bean2@2c6aed22
Bean不会被BeanFactory主动初始化,在首次获取这个Bean时初始化
如果需要的情况,可以调用预先实例化方法,提前创建
/* Bean对象一般在调用getBean获取时才创建, 也可以调用预先实例化方法提前创建 (只针对scope为单例的对象) */ beanFactory.preInstantiateSingletons();
2、自动装配的执行顺序
新增一个InterFaceType接口,Bean3和Bean4同时实现这个接口
在Bean1注册这个接口,Spring如何装配这个成员属性?
@Data
private static class Bean1 {
@Autowired
private Bean2 bean2;
// 1、指定声明bean名称
// @Autowired @Qualifier("bean4")
// private InterFaceType interFaceType;
// 2、或者变量名称也可以匹配bean名称
// @Autowired
// private InterFaceType bean4;
// 3、使用@Resource声明了名称,则优先级高于变量名称
// @Resource(name = "bean3")
// private InterFaceType bean4;
// 4、又加 @Autowired 又加 @Resource, 交给后处理器的顺序决定先由哪个注解解析器处理
@Autowired @Qualifier("bean4")
@Resource(name = "bean3")
private InterFaceType interFaceType;
}
private static class Bean2 {}
private interface InterFaceType {}
private static class Bean3 implements InterFaceType {}
private static class Bean4 implements InterFaceType {}
我们打印这个接口类型看看:
/*
* 可以看到默认是自动装配注解处理器先执行,所以bean4先被装填
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalCommonAnnotationProcessor
*/
log.info("InterFaceType Spring实际装填对象 -> {}", beanFactory.getBean(Bean1.class).getInterFaceType());
打印结果:
2023-02-08 15:22:30.444 INFO 23516 --- [ main] BeanFactoryTest : InterFaceType Spring实际装填对象 -> BeanFactoryTest$Bean4@3c46dcbe
若要改变注解的处理顺序,就改变Bean后置处理器类的处理顺序:
/* 更改后置处理器的添加顺序 将@Resource优先被添加执行 @Autowired滞后 */
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.sorted(beanFactory.getDependencyComparator())
.forEach(beanFactory::addBeanPostProcessor);
/*
* 默认是自动装配注解处理器先执行
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalCommonAnnotationProcessor
*/
log.info("InterFaceType Spring实际装填对象 -> {}", beanFactory.getBean(Bean1.class).getInterFaceType());
打印结果:
2023-02-08 15:29:52.865 INFO 32756 --- [ main] BeanFactoryTest : InterFaceType Spring实际装填对象 -> BeanFactoryTest$Bean3@3c46dcbe
3、排序比较器对象
基于这个对象来决定处理器的先后顺序
beanFactory.getDependencyComparator()

在一开始的BeanFactory注册中就已经放置了

比较器基于处理器的顺序属性决定先后:

这里在源码可以看到两个顺序值:

我们写个测试类比较便知:
@Test
public void processorOrderCompare() {
int orderForResource = Ordered.LOWEST_PRECEDENCE - 3;
int orderForAutowired = 2147483645;
log.info("@Resource -> {}, @Autowired -> {}", orderForResource, orderForAutowired);
log.info("@Resource > @Autowired ? {}", orderForResource > orderForAutowired);
}
打印结果:
2023-02-08 15:57:31.929 INFO 17840 --- [ main] BeanFactoryTest : @Resource -> 2147483644, @Autowired -> 2147483645 2023-02-08 15:57:31.931 INFO 17840 --- [ main] BeanFactoryTest : @Resource > @Autowired ? false
三、ApplicationContextImpl的实现
4种上下文的实现方式配置:
package cn.cloud9.spring;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.Controller;
import java.net.URL;
@Slf4j
public class ApplicationContextImpl {
public static void main(String[] args) {
classpathXmlApplicationContext();
systemXmlApplicationContext();
annotationConfigApplicationContext();
webServletApplicationContext();
}
/**
* @author OnCloud9
* @date 2023/2/8 16:30
* @description xml方式配置bean
* @params []
* @return void
*/
private static void classpathXmlApplicationContext() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("context1.xml");
for (String beanDefinitionName : classPathXmlApplicationContext.getBeanDefinitionNames()) {
log.info("xmlRegisteredBean: {}", beanDefinitionName);
}
log.info("inside bean2 is {}", classPathXmlApplicationContext.getBean(Bean1.class).getBean2());
}
/**
* @author OnCloud9
* @date 2023/2/8 16:35
* @description 文件系统方式读取xml配置bean
* @params []
* @return void
*/
private static void systemXmlApplicationContext() {
URL resource = ApplicationContextImpl.class.getClassLoader().getResource("context1.xml");
String path = resource.getPath();
FileSystemXmlApplicationContext fsXmlApplicationContext = new FileSystemXmlApplicationContext(path);
for (String beanDefinitionName : fsXmlApplicationContext.getBeanDefinitionNames()) {
log.info("systemXmlRegisteredBean: {}", beanDefinitionName);
}
log.info("inside bean2 is {}", fsXmlApplicationContext.getBean(Bean1.class).getBean2());
}
/**
* @author OnCloud9
* @date 2023/2/8 16:35
* @description 当前配置类方式实现Bean配置
* @params []
* @return void
*/
private static void annotationConfigApplicationContext() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfigurationClass.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
log.info("javaAnnotationBean: {}", beanDefinitionName);
}
log.info("inside bean2 is {}", applicationContext.getBean(Bean1.class).getBean2());
}
/**
* @author OnCloud9
* @date 2023/2/9 09:10
* @description WebServlet应用上下文对象Bean配置
* @params []
* @return void
*/
private static void webServletApplicationContext() {
AnnotationConfigServletWebServerApplicationContext applicationContext =
new AnnotationConfigServletWebServerApplicationContext(WebMvcConfig.class);
}
@Data
static class Bean1 {
private Bean2 bean2;
}
static class Bean2 {}
@Configuration
static class BeanConfigurationClass {
@Bean
public Bean1 bean1(Bean2 bean2) {
Bean1 bean1 = new Bean1();
bean1.setBean2(bean2);
return bean1;
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
@Configuration
static class WebMvcConfig {
/* ServletWeb服务器工厂对象配置,默认按Tomcat实现 */
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
/* 配置前置请求分发处理器 */
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
/* 分发注册Bean */
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
/* 直接注册一个控制器 */
@Bean("/controller1")
public Controller controller() {
return (request, response) -> {
response.getWriter().write("这是配置类的Controller!");
return null;
};
}
}
}
XML方式的配置文件(context1.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bean1" class="cn.cloud9.spring.ApplicationContextImpl.Bean1" >
<property name="bean2" ref="bean2" />
</bean>
<bean id="bean2" class="cn.cloud9.spring.ApplicationContextImpl.Bean2" />
<!--
后处理器的注册
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
-->
<context:annotation-config />
</beans>

浙公网安备 33010602011771号