本文共 26727 字,大约阅读时间需要 89 分钟。
注释:用文字描述程序,给程序员看的;
注解:说明程序的,给计算机看的。
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
概念描述:
JDK1.5之后的新特性
说明程序的
使用注解:@注解名称
作用分类:
/** * 注解javadoc演示 * * @version 1.0 * @since 1.5 */public class AnnoDemo1 { /** * 计算两数的和 * @param a 整数 * @param b 整数 * @return 两数的和 */ public int add(int a, int b ){ return a + b; }}
JDK中预定义的一些注解:
@SuppressWarnings("all")
格式:
public @interface 注解名称{ 属性列表;}
本质:注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation {}
属性:接口中的抽象方法
属性的返回值类型有下列取值:
public @interface MyAnno { int value(); Person per(); MyAnno2 anno2(); String[] strs(); String name() default "张三";}
定义了属性,在使用时需要给属性赋值:
@MyAnno(value=12, per = Person.P1, anno2 = @MyAnno2, strs="bbb")public class Worker { }
元注解:用于描述注解的注解
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到。
@Target({ ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface MyAnno3 { }@MyAnno3public class Worker { @MyAnno3 public String name = "aaa"; @MyAnno3 public void show(){ }}
在程序使用(解析)注解:获取注解中定义的属性值。
@Pro(className = "top.tjtulong.annotation.Demo1",methodName = "show")public class ReflectTest { public static void main(String[] args) throws Exception { Pro an = reflectTestClass.getAnnotation(Pro.class); // 调用注解对象中定义的抽象方法,获取返回值 String className = an.className(); String methodName = an.methodName(); System.out.println(className); System.out.println(methodName); }}
public class ProImpl implements Pro{ public String className(){ return "top.tjtulong.annotation.Demo1"; } public String methodName(){ return "show"; }}
@Configuration
:指定配置类;
@Component
:用于把当前类对象存入spring容器中;
以下三个注解的作用与@Component完全一样,它们是spring提供的更明确的划分,使三层对象更加清晰:
@Controller
:用于表现层;
@Service
:用于业务层;
@Repository
:用于持久层;
@Bean
:给容器中注册一个Bean对象,类型为返回值的类型,id默认是用方法名作为id;
@ComponentScans
:指明多个注解扫描的包;
@ComponentScan
:指明注解扫描的包,属性包括:
@Scope
:调整Bean实例的作用域,共有4种:
@Lazy
:懒加载,容器启动不创建对象,第一次获取Bean时再创建对象并初始化;
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.FilterType;import org.springframework.context.annotation.ComponentScan.Filter;import org.springframework.context.annotation.ComponentScans;import top.tjtulong.bean.Person;// 配置类==配置文件@Configuration // 告诉Spring这是一个配置类@ComponentScans( value = { @ComponentScan(value="top.tjtulong",includeFilters = { @Filter(type=FilterType.ANNOTATION, classes={ Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE, classes={ BookService.class}), @Filter(type=FilterType.CUSTOM, classes={ MyTypeFilter.class}) },useDefaultFilters = false) })public class MainConfig { //给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id @Scope("prototype") @Bean("person") public Person person01(){ return new Person("lisi", 20); }}public class Person { private String name; private Integer age; //get() set() toString()... }
自定义的包扫描过滤规则:
public class MyTypeFilter implements TypeFilter { /** * metadataReader:读取到的当前正在扫描的类的信息 * metadataReaderFactory:可以获取到其他任何类信息的 */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // TODO Auto-generated method stub //获取当前类注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //获取当前正在扫描的类的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前类资源(类的路径) Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("--->"+className); if(className.contains("er")){ return true; } return false; }}
@Condition
:按照一定的条件进行判断,满足条件给容器中注册bean,可以放在类上,也可以放在方法上;
@Import
:导入组件,id默认是组件的全类名;
//类中组件统一设置,满足当前条件,这个类中配置的所有bean注册才能生效;@Conditional({ WindowsCondition.class})@Configuration@Import({ Color.class, Red.class, MyImportBeanDefinitionRegistrar.class})public class MainConfig2 { /** * 如果系统是windows,给容器中注册("bill") * 如果是linux系统,给容器中注册("linus") */ @Bean("bill") public Person person01(){ return new Person("Bill Gates",62); } @Conditional(LinuxCondition.class) @Bean("linus") public Person person02(){ return new Person("linus", 48); }}
Condition类:
//判断是否linux系统public class LinuxCondition implements Condition { /** * ConditionContext:判断条件能使用的上下文(环境) * AnnotatedTypeMetadata:注释信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // TODO是否linux系统 //1、能获取到ioc使用的beanfactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); //2、获取类加载器 ClassLoader classLoader = context.getClassLoader(); //3、获取当前环境信息 Environment environment = context.getEnvironment(); //4、获取到bean定义的注册类 BeanDefinitionRegistry registry = context.getRegistry(); String property = environment.getProperty("os.name"); if(property.contains("linux")){ return true; } return false; }}
实现ImportBeanDefinitionRegistrar手动注册bean到容器中:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类; * 把所有需要添加到容器中的bean;调用 * BeanDefinitionRegistry.registerBeanDefinition手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean definition = registry.containsBeanDefinition("top.tjtulong.bean.Red"); boolean definition2 = registry.containsBeanDefinition("top.tjtulong.bean.Blue"); if(definition && definition2){ //指定Bean定义信息 RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); //注册一个Bean,指定bean名 registry.registerBeanDefinition("rainBow", beanDefinition); } }}
给容器中注册组件方法汇总:
&colorFactoryBean
);@Beanpublic ColorFactoryBean colorFactoryBean(){ return new ColorFactoryBean();}//创建一个Spring定义的FactoryBeanpublic class ColorFactoryBean implements FactoryBean{ //返回一个Color对象,这个对象会添加到容器中 @Override public Color getObject() throws Exception { System.out.println("ColorFactoryBean...getObject..."); return new Color(); } @Override public Class getObjectType() { return Color.class; } //是否为单例 @Override public boolean isSingleton() { return false; }}
bean的生命周期是指:bean创建---->初始化---->销毁的过程
方法一:通过@Bean指定初始化和销毁方法
initMethod:初始化方法,destroyMethod:销毁方法。
@Componentpublic class Car { public Car(){ System.out.println("car constructor..."); } public void init(){ System.out.println("car ... init..."); } public void detory(){ System.out.println("car ... detory..."); }}
@ComponentScan("top.tjtulong.bean")@Configurationpublic class MainConfigOfLifeCycle { //@Scope("prototype") @Bean(initMethod="init", destroyMethod="detory") public Car car(){ return new Car(); }}
方法二:通过让Bean实现InitializingBean接口(定义初始化逻辑),DisposableBean接口(定义销毁逻辑)
@Componentpublic class Cat implements InitializingBean,DisposableBean { public Cat(){ System.out.println("cat constructor..."); } @Override public void destroy() throws Exception { System.out.println("cat...destroy..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("cat...afterPropertiesSet..."); }}
方法三:可以使用JSR250
@PostConstruct
:在bean创建完成并且属性赋值完成,来执行初始化方法;@PreDestroy
:在容器销毁bean之前通知我们进行清理工作;@Componentpublic class Dog implements ApplicationContextAware { public Dog(){ System.out.println("dog constructor..."); } //对象创建并赋值之后调用 @PostConstruct public void init(){ System.out.println("Dog....@PostConstruct..."); } //容器移除对象之前 @PreDestroy public void detory(){ System.out.println("Dog....@PreDestroy..."); }}
以上三种初始化方法的执行顺序为:Constructor > @PostConstruct >InitializingBean > init-method
三种销毁方法的执行顺序为:@preDestroy >DisposableBean接口 > @Bean(destroyMethod)
方法四:BeanPostProcessor接口(bean的后置处理器)
在bean初始化前后进行一些处理工作:
/** * 后置处理器:初始化前后进行处理工作 * 将后置处理器加入到容器中 */@Componentpublic class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean); return bean; }}
BeanPostProcessor的原理
在refresh()
方法中的finishBeanFactoryInitialization(beanFactory);
方法执行时bean进行初始化。
step1:populateBean(beanName, mbd, instanceWrapper);
给bean进行属性赋值
initializeBean();
初始化bean对象 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);invokeInitMethods(beanName, wrappedBean, mbd); //执行自定义初始化applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
遍历得到容器中所有的BeanPostProcessor
,逐个执行beforeInitialization
,一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization()
。
p.s. bean的赋值、注入其它组件、@Autowired、生命周期注解功能、@Async等功能都是通过BeanPostProcessor实现。
参考:https://blog.csdn.net/weixin_34054931/article/details/91397723
使用@Value
赋值:
#{}
${}
,取出配置文件【properties】中的值(在运行环境变量里面的值)public class Person { @Value("张三") private String name; @Value("#{20-2}") private Integer age; @Value("${person.nickName}") private String nickName;}
配置类:
// 使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;// 加载完外部的配置文件以后使用${}取出配置文件的值@PropertySource(value={ "classpath:/person.properties"})@Configurationpublic class MainConfigOfPropertyValues { @Bean public Person person(){ return new Person(); }}
自动装配:Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值。
@Autowired
:自动注入,可以放在构造器,参数,方法,属性上
BookService { @Autowired BookDao bookDao;}
默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class),找到就赋值;
如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找。
@Qualifier("bookDao")
:使用@Qualifier指定需要装配的组件的id,而不是使用属性名;
自动装配默认一定要将属性赋值好,没有就会报错;可以使用@Autowired(required=false)
;
@Primary
:放在注解@Bean上,让Spring进行自动装配的时候,默认使用首选的bean;
Spring还支持使用@Resource
(JSR250)和@Inject
(JSR330) [java规范的注解]:
@Resource
:可以和@Autowired
一样实现自动装配功能,默认是按照组件名称进行装配的;但没有能支持@Primary
功能,也没有支持@Autowired(reqiured=false)
;
@Inject
:需要导入javax.inject的包,和@Autowired
的功能一样,但没有required=false
的功能;
p.s. @Autowired是Spring定义的;而@Resource、@Inject都是Java的规范。
都是通过AutowiredAnnotationBeanPostProcessor解析完成自动装配功能。
xxxAware接口
在Spring中有很多以Aware
结尾的接口,如果一个Bean实现了该接口,那么当该Bean被Spring初始化时,Spring会向该Bean注入相关资源(就是会回调接口中的方法)。作用是把Spring底层一些组件注入到自定义的Bean中。
示例:下面的TestService
实现了两个接口BeanNameAware
和ApplicationContextAware
接口。当Spring对bean进行初始化时,Spring会调用接口对应的方法。这样就可以获取到spring中的资源。
@Componentpublic class TestService implements BeanNameAware,ApplicationContextAware { private String beanName; private ApplicationContext context; @Override // 获取到bean的名称 public void setBeanName(String name) { System.out.println("name = " + name); beanName = name; } @Override // 获取上下文环境ApplicationContext public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("applicationContext = " + applicationContext); context = applicationContext; }}
常用的Aware相关接口作用:
接口名称 | 作用 |
---|---|
ApplicationContextAware | 获取spring 上下文环境的对象 |
BeanNameAware | 获取该bean在BeanFactory配置中的名字 |
BeanFactoryAware | 创建它的BeanFactory实例 |
ServletContextAware | 获取servletContext容器 |
ResourceLoaderAware | 获取ResourceLoader对象,通过它获得各种资源 |
通过ApplicationContextAwareProcessor实现。
具体实现参考:https://blog.csdn.net/baidu_19473529/article/details/81072524
@Profile
:指定组件在哪个环境的情况下才能被注册到容器中,若不指定,任何环境下都能注册这个组件。
便于开发环境、测试环境、生产环境之间的切换
@PropertySource("classpath:/dbconfig.properties")@Configurationpublic class MainConfigOfProfile implements EmbeddedValueResolverAware{ @Value("${db.user}") private String user; private StringValueResolver valueResolver; private String driverClass; @Profile("test") @Bean("testDataSource") public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setDriverClass(driverClass); return dataSource; } @Profile("dev") @Bean("devDataSource") public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud"); dataSource.setDriverClass(driverClass); return dataSource; } @Profile("prod") @Bean("prodDataSource") public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515"); dataSource.setDriverClass(driverClass); return dataSource; } @Override // 处理${}等特殊字符 public void setEmbeddedValueResolver(StringValueResolver resolver) { this.valueResolver = resolver; driverClass = valueResolver.resolveStringValue("${db.driverClass}"); }}
设置运行时设置profile的方式:
-Dspring.profiles.active=test
//1、使用无参构造创建一个applicationContextAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //2、设置需要激活的环境applicationContext.getEnvironment().setActiveProfiles("dev");//3、注册主配置类applicationContext.register(MainConfigOfProfile.class);//4、启动刷新容器applicationContext.refresh();
AOP动态代理:指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。
step:
joinPoint.procced()
);@Component("logger")@Aspect//表示当前类是一个切面类public class Logger { // 配置切入点 @Pointcut("execution(* io.github.tjtulong.service.impl.*.*(..))") private void pt1(){ } /** * 前置通知 */ @Before("pt1()") public void beforePrintLog(){ System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。"); } /** * 后置通知 */ @AfterReturning("pt1()") public void afterReturningPrintLog(){ System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。"); } /** * 异常通知 */ @AfterThrowing("pt1()") public void afterThrowingPrintLog(){ System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。"); } /** * 最终通知 */ @After("pt1()") public void afterPrintLog(){ System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。"); }}
阅读Sring源码的核心是:看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么。
@EnableAspectJAutoProxy
注解
@EnableAspectJAutoProxy的作用:
@Import(AspectJAutoProxyRegistrar.class)
:给容器中导入AspectJAutoProxyRegistrar
AspectJAutoProxyRegistrar
自定义给容器中注册bean;AnnotationAwareAspectJAutoProxyCreator
**,id为internalAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator类的层级结构图:
注意:实现了SmartInstantiationAwareBeanPostProcessor
与BeanFactoryAware
接口,说明该类为后置处理器(在bean初始化完成前后做事情)并自动装配了BeanFactory。
创建和注册AnnotationAwareAspectJAutoProxyCreator
的过程
step1:传入配置类,创建ioc容器;
step2:注册配置类,调用refresh()
刷新容器;
step3:registerBeanPostProcessors(beanFactory)
,注册bean的后置处理器来方便拦截bean的创建;
PriorityOrdered
接口的BeanPostProcessor;Ordered
接口的BeanPostProcessor;AnnotationAwareAspectJAutoProxyCreator
**,创建一个id为internalAutoProxyCreator
的BeanPostProcessor,流程为:1. 创建Bean的实例;2. populateBean():给bean的各种属性赋值;3. initializeBean():初始化bean; (1) invokeAwareMethods():处理Aware接口的方法回调 (2) applyBeanPostProcessorsBeforeInitialization():执行所有后置处理器的postProcessBeforeInitialization() (3) invokeInitMethods();执行自定义的初始化方法 (4) applyBeanPostProcessorsAfterInitialization():执行所有后置处理器的postProcessAfterInitialization()4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;
beanFactory.addBeanPostProcessor(postProcessor);
step4:finishBeanFactoryInitialization(beanFactory)
:完成BeanFactory初始化工作,创建剩下的单实例bean。
遍历获取容器中所有的Bean,依次创建对象getBean(beanName)
;
创建bean。AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()方法,其流程如下:
1. 先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;只要创建好的Bean都会被缓存起来2. createBean(),创建bean; (1)AnnotationAwareAspectJAutoProxyCreator会在任何bean创建之前先尝试返回bean的实例 【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】 【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】 (a) resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation 希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续(b) bean = applyBeanPostProcessorsBeforeInstantiation(): 拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor,就执行postProcessBeforeInstantiation if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } (b) doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例,与step3中一致
AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】的作用:
postProcessBeforeInstantiation()
;判断当前bean是否在advisedBeans中(保存了所有需要增强的bean)
判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否是切面(@Aspect)
postProcessAfterInitialization
return wrapIfNecessary(bean, beanName, cacheKey); //包装如果需要的情况下1. 获取当前bean的所有增强器(通知方法) Object[] specificInterceptors (1) 找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的); (2) 获取到能在bean使用的增强器; (3) 给增强器排序.2. 保存当前bean在advisedBeans中;3. 如果当前bean需要增强,创建当前bean的代理对象; (1) 获取所有增强器(通知方法) (2) 保存到proxyFactory (3) 创建代理对象:Spring自动决定 JdkDynamicAopProxy(config);jdk动态代理; ObjenesisCglibAopProxy(config);cglib的动态代理;4. 给容器中返回当前组件使用jdk/cglib增强了的代理对象;5. 以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
目标方法的执行:
CglibAopProxy.intercept()
:拦截目标方法的执行
核心:拦截器链
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; TargetSource targetSource = this.advised.getTargetSource(); try { ... target = targetSource.getTarget(); Class targetClass = (target != null ? target.getClass() : null); // 重点:将所有的MethodInterceptor串成一个链 List
拦截器链的触发过程:
参考:https://www.jianshu.com/p/1b557d22fad3
@EnableTransactionManagement@ComponentScan("top.tjtulong.tx")@Configurationpublic class TxConfig { //数据源 @Bean public DataSource dataSource() throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser("root"); dataSource.setPassword("123456"); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); return dataSource; } // 创建JdbcTemplate组件 @Bean public JdbcTemplate jdbcTemplate() throws Exception{ //Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件 JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource()); return jdbcTemplate; } //注册事务管理器在容器中 @Bean public PlatformTransactionManager transactionManager() throws Exception{ return new DataSourceTransactionManager(dataSource()); }}
@EnableTransactionManagement
功能与@EnableAspectJAutoProxy
类似,利用TransactionManagementConfigurationSelector
给容器中会导入两个组件:AutoProxyRegistrar
与ProxyTransactionManagementConfiguration
。
给容器中注册事务增强器;
在目标方法执行的时候,执行拦截器链
BeanFactoryPostProcessor
BeanFactory的后置处理器。在BeanFactory标准初始化之后调用,用来定制和修改BeanFactory的内容。
执行时机:所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建。
@Componentpublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory..."); // 获取容器中组件的数量 int count = beanFactory.getBeanDefinitionCount(); // 获取容器中全部组件的名称 String[] names = beanFactory.getBeanDefinitionNames(); System.out.println("当前BeanFactory中有"+ count +" 个Bean"); System.out.println(Arrays.asList(names)); }}
原理:ioc容器创建对象refresh() ——> invokeBeanFactoryPostProcessors(beanFactory);
直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法(在初始化创建其他组件前面执行)。
BeanDefinitionRegistryPostProcessor
继承于BeanFactoryPostProcessor,实现的方法为postProcessBeanDefinitionRegistry();
执行时机:在所有bean定义信息将要被加载,bean实例还未创建的;优先于BeanFactoryPostProcessor执行,利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件;
@Componentpublic class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor{ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量:"+beanFactory.getBeanDefinitionCount()); } //BeanDefinitionRegistry为Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例; @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { System.out.println("postProcessBeanDefinitionRegistry...bean的数量:"+registry.getBeanDefinitionCount()); //RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class); // 手动添加一个BeanDefinition AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition(); registry.registerBeanDefinition("hello", beanDefinition); }}
**原理:**ioc创建对象refresh() ——> invokeBeanFactoryPostProcessors(beanFactory);
ApplicationListener监听器
监听容器中发布的事件,事件驱动模型开发。
@Componentpublic class MyApplicationListener implements ApplicationListener{ //当容器中发布此事件以后,方法触发 @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("收到事件:"+event); }}
只要容器中有相关事件的发布,我们就能监听到这个事件:
applicationContext.publishEvent();
监听器的创建过程:refresh() ——>registerListeners();
从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中(注意此时并不初始化):
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
事件发布流程
publishEvent(new ContextRefreshedEvent(this));
getApplicationEventMulticaster()
;for (final ApplicationListener listener : getApplicationListeners(event, type)) { // 1.如果有Executor,可以支持使用Executor进行异步派发; Executor executor = getTaskExecutor(); // 2.否则,同步的方式直接执行listener方法; invokeListener(listener, event); // 3.拿到listener回调onApplicationEvent方法;}
事件多播器(派发器)
刷新容器refresh() ——>initApplicationEventMulticaster();
初始化ApplicationEventMulticaster
;
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster。