spring注解驱动
- 视频参考:尚硅谷雷丰阳老师spring注解驱动教程
- 源码、资料参考:尚硅谷官方资料
- 博客中代码使用环境:IDEA+Maven+Spring4.3.12+JDK1.8
1. 组件注册—@Configuration与@Bean
1.1 基于xml配置文件注入bean
准备工作:使用IDEA创建maven工程spring_annotation
,pom.xml中引入以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
</dependencies>
在java
目录下新建包名为com.trisirt.spring.annotation.bean
,包内新建一个Person
类:
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在resources
目录下新建beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册组件 -->
<bean id="person" class="com.trisirt.spring.annotation.bean.Person">
<property name="age" value="18"></property>
<property name="name" value="Tom"></property>
</bean>
</beans>
在com.trisirt.spring.annotation
包内新建主测试类MainTest.calss
public class MainTest {
public static void main(String[] args) {
// 基于xml注入JavaBean
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}
启动主程序测试注入结果:
1.2 基于注解方式注入bean
在com.trisirt.spring.annotation.config
包下新建配置类MainConfig.class
/**
* 使用配置类代替配置文件,实现完全注解开发
* 配置类本身也是一个组件
*/
@Configuration // 告诉spring这是一个配置类
public class MainConfig {
// 给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
@Bean
public Person person() {
return new Person("Jack", 20);
}
}
修改MainTest.calss
为使用注解注入的方式:
public class MainTest {
public static void main(String[] args) {
// 基于注解注入JavaBean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
}
}
测试结果如下:
实现注解注入后可以使用getBeanNamesForType()
方法获取Person类型的组件在IOC容器中的名字:
// MainTest.class中加入以下代码段
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
for (String name : namesForType) {
System.out.println(name); // 结果为:person
}
修改MainConfig.class
中方法名为person01
,可以看到容器中名字也对应被修改为person01
@Configuration
public class MainConfig {
@Bean
public Person person01() { // MainTest打印结果为:person01
return new Person("Jack", 20);
}
}
也可通过@Bean注解中的name或value属性指定容器中Person类的名字:
@Configuration
public class MainConfig {
@Bean(name="person_jack") // MainTest打印结果为:person_jack
public Person person01() {
return new Person("Jack", 20);
}
}
2. 组件注册—@ComponenScan
2.1 基于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 http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 包扫描、只要标注了@Controller、@Service、@Repository,@Component -->
<context:component-scan base-package="com.trisirt" use-default-filters="false"></context:component-scan>
</beans>
2.1 基于注解方式包扫描定义
准备工作:在com.trisirt.spring.annotation
包下分别创建controller.BookController.class
、service.BookService
、dao.BookDao
,仅作演示,不涉及具体业务逻辑:
@Controller
public class BookController {
}
@Service
public class BookService {
}
@Repository
public class BookDao {
}
在MainConfig.class
中使用@ComponentScan
注解定义扫描规则:
@Configuration // 告诉spring这是一个配置类
@ComponentScan(value = "com.trisirt")
// @ComponentScan value:指定要扫描的包
public class MainConfig {
// 给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
@Bean(name="person_jack")
public Person person01() {
return new Person("Jack", 20);
}
}
新建测试类进行测试,打印容器中所有的组件名称:
public class IOCTest {
@SuppressWarnings("resource")
@Test
public void test01() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
for(String name : names) {
System.out.println(name);
}
}
}
打印结果中除了IOC基本容器之外还有我们自己定义的mainConfig、bookController、bookDao、bookService、person_jack
等bean
@ComponentScan
还可以使用excludeFilters
或includeFilters
定义排除或包含规则:
@Configuration // 告诉spring这是一个配置类
// @ComponentScan
// value:指定要扫描的包
// excludeFilters = Filter[]:指定扫描的时候按照什么规则排除哪些组件
// includeFilters = Filter[]:指定扫描的时候只需要包含哪些组件
@ComponentScan(value = "com.trisirt", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MainConfig {
// 给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
@Bean(name="person_jack")
public Person person01() {
return new Person("Jack", 20);
}
}
可以看到加上以上excludeFilters
之后,打印结果中就没有bookController
和bookService
这两个bean了。
对于includeFilters
,需要注意只有加上useDefaultFilters = false规则才会生效,因为spring底层默认includeFilters包含所有组件
@Configuration // 告诉spring这是一个配置类
// @ComponentScan
// value:指定要扫描的包
// excludeFilters = Filter[]:指定扫描的时候按照什么规则排除哪些组件
// includeFilters = Filter[]:指定扫描的时候只需要包含哪些组件
@ComponentScan(value = "com.trisirt", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})},
useDefaultFilters = false
)
public class MainConfig {
// 给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
@Bean(name="person_jack")
public Person person01() {
return new Person("Jack", 20);
}
}
使用以上注解打印结果为mainConfig、bookController、person_jack
,不包含bookController
和bookService
这两个bean。
同一个配置类中,可以多次使用@ComponentScan
注解来定义扫描规则
另外,早期版本的jdk还提供@ComponentScans
注解,可以实现一次定义多个@ComponentScan
规则:
@ComponentScans(
value = {
@ComponentScan(value = "com.trisirt", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})},
useDefaultFilters = false)
})
3. 组件注册—自定义FilterType指定过滤规则
前面的@ComponentScan
中使用了@ComponentScan.Filter
注解,其中属性type
有以下五种:
FilterType.ANNOTATION
:按照注解FilterType.ASSIGNABLE_TYPE
:按照给定的类型FilterType.ASPECTJ
:按照AspectJ规则FilterType.REGEX
:按照正则FilterType.CUSTOM
:按照自定义
自定义过滤器规则:实现TypeFilter
接口,重写match()
方法,定义过滤规则:
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader 读取到的当前正在扫描的类信息
* @param metadataReaderFactory 可以获取到其他任何类信息
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类注释的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
// 打印类名信息
String className = classMetadata.getClassName();
System.out.println("--->" + className);
// 设置过滤规则为类名中包含"er"的类
if(className.contains("er"))
return true;
return false;
}
MainConfig
中使用自定义过滤器
@Configuration // 告诉spring这是一个配置类
// @ComponentScan
// value:指定要扫描的包
// excludeFilters = Filter[]:指定扫描的时候按照什么规则排除哪些组件
// includeFilters = Filter[]:指定扫描的时候只需要包含哪些组件
@ComponentScan(value = "com.trisirt", includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})},
useDefaultFilters = false)
public class MainConfig {
// 给容器中注册一个bean,类型为返回值的类型,id默认是用方法名作为id
@Bean(name="person_jack")
public Person person01() {
return new Person("Jack", 20);
}
}
运行测试程序test01()
结果如下:
--->com.trisirt.spring.annotation.bean.Person
--->com.trisirt.spring.annotation.config.MyTypeFilter
--->com.trisirt.spring.annotation.controller.BookController
--->com.trisirt.spring.annotation.dao.BookDao
--->com.trisirt.spring.annotation.MainTest
--->com.trisirt.spring.annotation.service.BookService
--->com.trisirt.spring.annotation.test.IOCTest
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
myTypeFilter
bookController
bookService
person_jack
组件注册–@Scope
@Configuration
public class MainConfig2 {
// @Scope:调整作用域
// prototype:多实例:IOC容器启动并不会去调用方法创建对象放到IOC容器中,每次获取的时候才会调用方法创建对象
// singleton:単实例(默认的):IOC容器启动会调用方法创建对象放到容器中,以后每次获取就是直接从容器中拿
// request:同一次请求创建一个实例
// session:同一个session创建一个实例
@Scope("prototype")
@Bean("person")
public Person person() {
return new Person("张三", 25);
}
}
组件注册–@Lazy
/*
懒加载:
単实例bean:默认在容器启动的时候创建对象
懒加载:容器启动不创建对象,第一次使用(获取)Bean创建对象,并初始化
*/
@Configuration
public class MainConfig2 {
@Lazy
@Bean("person")
public Person person() {
System.out.println("给容器中添加person...");
return new Person("张三", 25);
}
}
测试类代码增加打印语句,观察输出显示容器创建和向容器添加Person的次序:
@Test
public void test02() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("ioc容器创建完成...");
Object bean1 = applicationContext.getBean("person");
Object bean2 = applicationContext.getBean("person");
System.out.println(bean1 == bean2);
}
使用@lazy注解之后是懒加载模式,先创建容器,再注入person,打印结果如下:
ioc容器创建完成...
给容器中添加person...
true
组件注册–@Conditional
@Conditional
可以放在方法或者类名上方,放在类名上方:类中组件统一设置。表示满足该条件时,这个类中配置的所有bean注册才能生效。
Mainconfig2
类新增加两个组件(“bill"和"linus”)注册定义,使用@Conditional
注解需要传入Condition[]
数组作为条件,条件定义如下:
@Configuration
public class MainConfig2 {
@Bean("person")
public Person person() {
//System.out.println("给容器中添加person...");
return new Person("张三", 25);
}
/**
* @Conditional({Condition}):按照一定条件进行判断,满足条件给容器中注册bean
*
* 需求:
* 如果系统是windows,给容器中注册("bill")
* 如果系统是linux,给容器中注册("linus")
*/
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 66);
}
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02() {
return new Person("Linus Torvalds", 52);
}
}
在com.trisirt.spring.annotation.condition
包下新建两个类:WindowsCondition
和LinuxCondition
,用于定义判断操作系统类型的条件
// 判断是否linux系统
public class LinuxCondition implements Condition {
/**
*
* @param conditionContext 判断条件能使用的上下文环境
* @param annotatedTypeMetadata 注释信息
* @return
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 判断是否linux系统
// 1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
// 2、获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
// 3、获取当前环境信息
Environment environment = conditionContext.getEnvironment();
// 4、获取bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
// 可以判断容器中bean注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");
String OSName = environment.getProperty("os.name");
if(OSName.contains("Linux")) {
return true;
}
return false;
}
}
// 判断是否windows操作系统
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String OSName = environment.getProperty("os.name");
if(OSName.contains("Windows")) {
return true;
}
return false;
}
}
新建测试方法test03()
@Test
public void test03() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 动态获取环境变量的值:Windows 10
String OSName = environment.getProperty("os.name");
System.out.println(OSName);
String[] names = applicationContext.getBeanNamesForType(Person.class);
for(String name : names) {
System.out.println(name);
}
Map<String, Person> persons = applicationContext.getBeansOfType(Person.class);
System.out.println(persons);
}
由于当前系统为Win10,因此测试结果如下:
Windows 10
person
bill
{person=Person{name='张三', age=25}, bill=Person{name='Bill Gates', age=66}}
为了测试Linux系统的效果,可以在IDEA运行控制页面上选择Edit Configurations...
,在虚拟机参数VM options
一栏中输入:-Dos.name=Linux
,再次运行即可得到如下结果:
Linux
person
linus
{person=Person{name='张三', age=25}, linus=Person{name='Linus Torvalds', age=52}}
组件注册–@Import
在bean
包下新建Clolor
和Red
两个类,使用@Import
可直接导入
@Configuration
// 导入组件,id默认是组件的全类名
@Import({Color.class, Red.class})
public class MainConfig2 {
@Bean("person")
public Person person() {
return new Person("张三", 25);
}
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 66);
}
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02() {
return new Person("Linus Torvalds", 52);
}
/**
* 给容器中注册组件:
* 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
* 2)、@Bean[导入第三方包里面的组件]
* 3)、@Import[快速给容器中导入一个组件]
* 1)、@Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
* 2)、@ImportSelector:返回需要到导入的组件的全类名数组
* 3)、@ImportBeanDefinitionRegistrar:手动注册bean到容器中
*/
}
使用ImportSelector
在bean
包下新建Blue
和Yellow
两个类,在condition
包下新建MyImportSelector
类,返回要导入的组件的全类名数组
// 自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
/**
*
* @param annotationMetadata 当前标注@Import注解的类的所有注解信息
* @return 返回值就是要导入到容器中的组件全类名
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 方法不要返回null值
//return new String[0];
return new String[]{"com.trisirt.spring.annotation.bean.Blue", "com.trisirt.spring.annotation.bean.Yellow"};
}
}
使用上面自定义的MyImportSelector.class
作为@Import
的参数
@Configuration
// 导入组件,id默认是组件的全类名
@Import({Color.class, Red.class, MyImportSelector.class})
public class MainConfig2 {
@Bean("person")
public Person person() {
return new Person("张三", 25);
}
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 66);
}
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02() {
return new Person("Linus Torvalds", 52);
}
/**
* 给容器中注册组件:
* 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
* 2)、@Bean[导入第三方包里面的组件]
* 3)、@Import[快速给容器中导入一个组件]
* 1)、@Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
* 2)、@ImportSelector:返回需要到导入的组件的全类名数组
* 3)、@ImportBeanDefinitionRegistrar:手动注册bean到容器中
*/
}
使用ImportBeanDefinitionRegistrar
在bean
包下新建RainBow
类,在condition
包下新建MyImportBeanDefinitionRegistrar
类,手动注册bean到容器中
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param annotationMetadata 当前类的注解信息
* @param beanDefinitionRegistry BeanDefinition注册类
* 把所有需要添加到容器中的bean,调用beanDefinitionRegistry.registerBeanDefinition()手工注册进来
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
boolean definition1 = beanDefinitionRegistry.containsBeanDefinition("com.trisirt.spring.annotation.bean.Red");
boolean definition2 = beanDefinitionRegistry.containsBeanDefinition("com.trisirt.spring.annotation.bean.Blue");
if(definition1 && definition2) {
// 指定Bean的定义信息:(Bean的类型,生命周期...)
BeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
// 注册一个bean,指定bean名
beanDefinitionRegistry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
修改MainConfig2
定义,使用上面自定义的``MyImportBeanDefinitionRegistrar.class作为
@Import`的参数
@Configuration
// 导入组件,id默认是组件的全类名
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
@Bean("person")
public Person person() {
return new Person("张三", 25);
}
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 66);
}
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02() {
return new Person("Linus Torvalds", 52);
}
/**
* 给容器中注册组件:
* 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
* 2)、@Bean[导入第三方包里面的组件]
* 3)、@Import[快速给容器中导入一个组件]
* 1)、@Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
* 2)、@ImportSelector:返回需要到导入的组件的全类名数组
* 3)、@ImportBeanDefinitionRegistrar:手动注册bean到容器中
*/
}
新建测试方法testImport()
:
@Test
public void testImport() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
printBeans(applicationContext);
}
private void printBeans(AnnotationConfigApplicationContext applicationContext) {
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for(String name : definitionNames) {
System.out.println(name);
}
}
测试发现自定义的rainBow
组件已经加入容器中,原因是前面判断com.trisirt.spring.annotation.bean.Red
和com.trisirt.spring.annotation.bean.Blue
是否存在于容器中的条件均为真,因此手动创建了一个名为rainBow
的组件并加入容器中,测试程序打印结果如下:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.trisirt.spring.annotation.bean.Color
com.trisirt.spring.annotation.bean.Red
com.trisirt.spring.annotation.bean.Blue
com.trisirt.spring.annotation.bean.Yellow
person
bill
rainBow
组件注册–使用FactoryBean
在bean
包下新建ColorFactoryBean
类
// 创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回一个Color对象,这个对象会添加到容器中
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
// 是单例?
// true:这个bean是単实例,在容器中保存一份
// false:多实例,每次获取都会创建一个新的bean
@Override
public boolean isSingleton() {
return true;
}
}
修改MainConfig2
定义,增加colorFactoryBean
组件注册的定义:
@Configuration
// 导入组件,id默认是组件的全类名
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
@Bean("person")
public Person person() {
//System.out.println("给容器中添加person...");
return new Person("张三", 25);
}
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 66);
}
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02() {
return new Person("Linus Torvalds", 52);
}
/**
* 给容器中注册组件:
* 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
* 2)、@Bean[导入第三方包里面的组件]
* 3)、@Import[快速给容器中导入一个组件]
* 1)、@Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
* 2)、@ImportSelector:返回需要到导入的组件的全类名数组
* 3)、@ImportBeanDefinitionRegistrar:手动注册bean到容器中
* 4)、使用Spring提供的FactoryBean(工厂Bean)
* 1)、默认获取到的是工厂bean,调用getObject创建的对象
* 2)、要获取工厂Bean本身,我们需要给id前面加一个&,即&colorFactoryBean
*/
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
}
修改测试程序testImport()
:
@Test
public void testImport() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
printBeans(applicationContext);
// 工厂Bean获取的是调用getObject创建的对象
Object bean = applicationContext.getBean("colorFactoryBean");
Object bean2 = applicationContext.getBean("colorFactoryBean");
System.out.println("bean的类型:" + bean.getClass());
System.out.println(bean == bean2);
}
测试结果如下:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.trisirt.spring.annotation.bean.Color
com.trisirt.spring.annotation.bean.Red
com.trisirt.spring.annotation.bean.Blue
com.trisirt.spring.annotation.bean.Yellow
person
bill
colorFactoryBean
rainBow
ColorFactoryBean...getObject...
bean的类型:class com.trisirt.spring.annotation.bean.Color
true