一、BeanDefinition 接口
说到BeanDefinition,就要说到java的核心思想了,万物皆对象。众所周知,java是面向对象的编程语言,所有的事务都可以用一个对象来描述,jdk提供了用来描述类的类Class,spring为了能更好的描述bean,也提供了一个类,那就是BeanDefinition。简而言之,BeanDefinition就是用来描述bean的类。
执行时机:读取bean时,就会使用,生成对应的BeanDefinition对象
/** * * BeanDefinition用来描述bean的类,该实例具有属性值。 * */ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { /** * 单例 * */ String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; /** * 原型即多例 * */ String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; /** * */ int ROLE_APPLICATION = 0; /** * * ROLE_SUPPORT = 1 表示这个类是用户本身的,是从配置文件中过来的 */ int ROLE_SUPPORT = 1; /** * * ROLE_INFRASTRUCTURE = 2 表示这个bean是spring自己的 */ int ROLE_INFRASTRUCTURE = 2; /** * 父类的名字 */ void setParentName(@Nullable String parentName); @Nullable String getParentName(); /** * bean 的 class name */ void setBeanClassName(@Nullable String beanClassName); @Nullable String getBeanClassName(); /** * 作用域 */ void setScope(@Nullable String scope); @Nullable String getScope(); /** * 是否懒加载 */ void setLazyInit(boolean lazyInit); boolean isLazyInit(); /** * 依赖 */ void setDependsOn(@Nullable String... dependsOn); @Nullable String[] getDependsOn(); void setAutowireCandidate(boolean autowireCandidate); /** * * 是否启用自动装配 */ boolean isAutowireCandidate(); /** * primary标注,表示优先注入,优先使用 */ void setPrimary(boolean primary); boolean isPrimary(); /** * 工厂名字 * */ void setFactoryBeanName(@Nullable String factoryBeanName); @Nullable String getFactoryBeanName(); /** * 工厂方法名字 */ void setFactoryMethodName(@Nullable String factoryMethodName); @Nullable String getFactoryMethodName(); /** * * 返回此bean的构造函数参数值。 */ ConstructorArgumentValues getConstructorArgumentValues(); /** * * 构造方法是否有构造参数 * @since 5.0.2 */ default boolean hasConstructorArgumentValues() { return !getConstructorArgumentValues().isEmpty(); } MutablePropertyValues getPropertyValues(); /** * Return if there are property values values defined for this bean. * @since 5.0.2 */ default boolean hasPropertyValues() { return !getPropertyValues().isEmpty(); } /** * * spring bean初始化完成调用的方法的名字 * */ void setInitMethodName(@Nullable String initMethodName); @Nullable String getInitMethodName(); /** * spring bean销毁前调用的方法的名字 */ void setDestroyMethodName(@Nullable String destroyMethodName); @Nullable String getDestroyMethodName(); void setRole(int role); int getRole(); /** * * bean 描述 * Set a human-readable description of this bean definition. * @since 5.1 */ void setDescription(@Nullable String description); @Nullable String getDescription(); // Read-only attributes /** * * 是否是单例 */ boolean isSingleton(); /** * 是否是原型 即多例 */ boolean isPrototype(); /** * * 是否是抽象 */ boolean isAbstract(); @Nullable String getResourceDescription(); @Nullable BeanDefinition getOriginatingBeanDefinition(); }
从源码中可以看出BeanDefinition具有多个属性,可以用来描述bean,其中beanClassName可以用来存储bean的class,方便后面通过反射创建对象。scope、lazyInit、autowireCandidate等也都是重要属性。
- BeanMetadataElement接口:BeanDefinition元数据,返回该Bean的来源
- AttributeAccessor接口:提供对BeanDefinition属性操作能力,
- AbstractBeanDefinition类:抽象类统一实现了BeanDefinition定义的一部分操作,可以说是定义了BeanDefinition很多默认的属性。 正是在AbstractBeanDefinition基础上, Spring衍生出了一些列BeaDefinition。
-
RootBeanDefinition:代表一个xml,java Config来的BeanDefinition
-
ChildBeanDefinition:可以让子BeanDefinition定义拥有从父母哪里继承配置的能力
-
GenericBeanDefinition:spring2.5后注册bean首选的是GenericBeanDefinition。GenericBeanDefinition允许动态的设置父bean.GenericBeanDefinition可以作为RootBeanDefinition与ChildBeanDefinition的替代品。
-
AnnotatedBeanDefinition接口:表示注解类型BeanDefinition。有两个重要的属性,AnnotationMetadata,MethodMetadata分别表示BeanDefinition的注解元信息和方法元信息
实现了此接口的BeanDefinition可以获取到注解元数据和方法元数据。 -
AnnotatedGenericBeanDefinition类:表示@Configuration注解注释的BeanDefinition类
-
ScannedGenericBeanDefinition类:表示@Component、@Service、@Controller等注解注释的Bean类
BeanDefinitionRegistry 接口
![](https://img2020.cnblogs.com/blog/660329/202011/660329-20201122110013563-456795318.png)
BeanDefinitionReader接口
既可以使用BeanDefinitionRegistry构造。也可以通过loadBeanDefinitions把配置加载为多个BeanDefinition并注册到BeanDefinitionRegistry中。可以说是高效版本的BeanDefinitionRegistry。
实现类有
- XmlBeanDefinitionReader从xml中读取BeanDefinition;
- PropertiesBeanDefinitionReader从Properties文件读取BeanDefinition
AnnotatedBeanDefinitionReader类
对带有注解的BeanDefinition进行注册
ClassPathBeanDefinitionScanner类
可以扫描到@Component @Repository @Service @Controller 的BeanDefinition注册到容器中。
BeanDefinitionHolder
二、BeanFactory和FactoryBean
有很多人弄不清楚BeanFactory和FactoryBean的区别,BeanFactory是创建bean的工厂,我们常说的spring 容器(存储spring bean的map)就是在BeanFactory中定义的。而FactoryBean是spring提供的一个特殊的bean,通过FactoryBean我们也可以将一个普通class注册到spring容器中。
BeanFactory
Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
从源码中可以看出BeanFactory提供了很多getBean方法,这个方法就是根据不同的参数来获取bean对象。BeanFactory是一个工厂用来存储和创建bean的。
FactoryBean
FactoryBean是spring提供的一个特殊的bean,实现此接口的bean可以往spring容器中添加一个bean。
@Component("indexFactoryBean") public class IndexFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { IndexDao indexDao = new IndexDao(); return indexDao; } @Override public Class<?> getObjectType() { return IndexDao.class; } } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Object indexFactoryBean = context.getBean("indexFactoryBean"); System.out.println(indexFactoryBean.getClass()); } }
执行结果:
indexDao class com.wangcongming.demo.service.IndexDao
可以发现IndexFactoryBean注册到spring容器中的对象是IndexDao,这就是spring中FactoryBean提供的功能。FactoryBean中getObject()方法可以返回一个对象,spring容器初始化的过程中会将getObject()返回的对象添加到spring容器中。那么如果想获取IndexFactoryBean本身的对象怎么办呢?只需在bean name前加&即可取出
public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Object indexFactoryBean = context.getBean("indexFactoryBean"); System.out.println(indexFactoryBean.getClass()); Object indexFactoryBean2 = context.getBean("&indexFactoryBean"); System.out.println(indexFactoryBean2.getClass()); } }
执行结果:
indexDao class com.wangcongming.demo.service.IndexDao class com.wangcongming.demo.service.IndexFactoryBean
三、BeanFactoryPostProcessor
执行时机:工厂初始化完成之后,在bean被创建成对象之前执行
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
BeanFactoryPostProcessor 工厂后置处理器,它是在工厂初始化完成之后调用,它可以对bean进行修改,是spring提供的一个扩展点。postProcessBeanFactory()方法将factory传入进去了,可以通过factory进行操作。
BeanDefinitionRegistryPostProcessor
执行时机:是BeanFactoryPostProcessor的子类,会在BeanFactoryPostProcessor之前进行执行
它是BeanFactoryPostProcessor的扩充接口,他扩充了一个方法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
可以看到这个方法将registry传入进来了,这意味着我们可以通过registry向容器中添加bean
四、BeanPostProcessor
bean后置处理器,会在bean初始化完成之后回调该接口的方法。
执行时机:bean对象创建完成,还未放入容器中时执行
@Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }
这两个方法有什么区别呢? postProcessBeforeInitialization方法会在postProcessAfterInitialization之前回调,值得注意的是postProcessAfterInitialization方法的回调是在所有的BeanPostProcessor的postProcessBeforeInitialization方法执行完成之后。
五、InitializingBean
InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法(创建出bean实例后)。
在spring初始化bean的时候,如果该bean是实现了InitializingBean接口,并且同时在配置文件中指定了init-method,系统则是先调用afterPropertiesSet方法,然后在调用init-method中指定的方法。
spring要求这个init-method方法是一个无参数的方法。
注意这个顺序:
- @PostConstruct注解标注的方法(JSR250)
- 实现InitializingBean接口的afterPropertiesSet方法(Spring的接口)
- 使用@Bean注解属性initMethod自定义的方法(Spring提供)
六、DisposableBean
该接口的作用是:允许在容器销毁该bean的时候获得一次回调。DisposableBean接口也只规定了一个方法:destroy。
关于在spring 容器初始化 bean 和销毁前所做的操作定义方式还有以下种:
- 通过@PostConstruct和@PreDestroy注解实现初始化和销毁bean之前进行的操作。
- 通过在xml中定义init-method和destory-method方法。
注意:
多例bean的生命周期不会由Spring容器来管理,说的简单一点,多例bean其实就是自生自灭的,和容器没有关系。 ,这里的DisposableBean中的方法是由Spring容器来调用的,所以如果一个多例实现了DisposableBean是没有啥意义的,因为相应的方法根本不会被调用,当然在XML配置文件中指定了destroy方法,也是没有意义的。
七、**Aware接口
Spring框架提供了多个*Aware接口,用于辅助Spring Bean以编程的方式调用Spring容器。通过实现这些接口,可以增强Spring Bean的功能,但是也会造成对Spring容器的绑定。
- ApplicationContextAware:Spring框架启动时,ApplicationContext初始化实现了该接口的Spring Bean时,会将ApplicationContext的引用作为参数传递给创建的Bean实例,创建的Bean实例可以通过ApplicationContext的引用操作Spring框架的各种资源。
- ApplicationEventPublisherAware:应用事件发布器,用于发布事件。
- BeanClassLoaderAware:加载Spring Bean的类加载器。
- BeanFactoryAware:获得当前bean Factory,从而调用容器的服务
- BootstrapContextAware:资源适配器BootstrapContext,如JCA,CCI
- BeanNameAware:获得到容器中Bean的名称
- EmbeddedValueResolverAware:通过 EmbeddedValueResolverAware 接口可以获取spring容器加载的一些属性值。
- EnvironmentAware:获取Environment对象。Environment是Spring的核心组件之一,可以理解为ApplicationContext的运行时环境,从中我们可以获取操作系统信息、配置文件(application.properties等)中定义的属性信息等。
- ImportAware:可以获取到导入该配置类接口的数据配置,是需要与@Import一起使用的。
- MessageSourceAware:得到message source从而得到文本信息
- NotificationPublisherAware:JMX通知
- ResourceLoaderAware:获取资源加载器,可以获得外部资源文件
- ServletConfigAware:获取ServletConfig
- ServletContextAware:获取ServletContext
ApplicationContextAware
1、为什么需要ApplicationContextAware?
在某些类中我们经常需要通过ApplicationContext来获取需要的bean,但每一次使用new ClassPathXmlApplicationContext()都会重新装配文件并实例化上下文bean,这样肯定是很麻烦的,此时ApplicationContextAware接口的作用就体现出来了——spring会给实现此接口的类注入ApplicationContext对象
2、如何使用?
通常我们是写一个AppContextUtil工具类
mport org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class AppContextUtil implements ApplicationContextAware { // 定义静态ApplicationContext private static ApplicationContext applicationContext = null; /** * 重写接口的方法,该方法的参数为框架自动加载的IOC容器对象 * 该方法在启动项目的时候会自动执行,前提是该类上有IOC相关注解,例如@Component * @param applicationContext ioc容器 * @throws BeansException e */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 将框架加载的ioc赋值给全局静态ioc AppContextUtil.applicationContext = applicationContext; log.info("==================ApplicationContext加载成功=================="); } // 获取applicationContext public static ApplicationContext getApplicationContext() { return applicationContext; } // 通过name获取 Bean. public static Object getBean(String name) { return getApplicationContext().getBean(name); } // 通过class获取Bean. public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } // 通过name,以及Clazz返回指定的Bean public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
3、spring何时注入上下文?
通过源码跟踪了解到AbstractApplicationContext.class下的refresh()方法中的prepareBeanFactory这句跟Aware有关,我们还可以看到:ApplicationContextAware是在spring初始化完bean后才注入上下文的
prepareBeanFactory方法中涉及到上图红圈圈这个类,此类中的方法postProcessBeforeInitialization调用了此类中的invokeAwareInterfaces方法:
看到没,上图画圈圈的地方就是spring对实现ApplicationContextAware接口的类调用setApplicationContext进行上下文注入
八、ApplicationEvent抽象类
是个抽象类,里面只有一个构造函数和一个长整型的timestamp。
spring事件使用步骤如下:
- 自定义事件:实现ApplicationEvent。
- 定义监听器:实现 ApplicationListener
- 使用容器对事件进行发布
1、自定义事件
public class TestEvent extends ApplicationEvent { private String name; private String msg; public TestEvent(Object source){ super(source); } public TestEvent(Object source, String name, String msg) { super(source); this.name = name; this.msg = msg; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
2、定义监听器
@Component public class TestEventListener implements ApplicationListener<TestEvent> { @Override public void onApplicationEvent(TestEvent testEvent) { System.out.println("姓名:"+testEvent.getName()+"得到消息:"+testEvent.getMsg()); } }
3、使用容器发布事件
@Component public class TestEventPublisher { @Autowired private ApplicationContext applicationContext; public void pushlish(String name, String msg){ applicationContext.publishEvent(new TestEvent(this, name,msg)); } }
九、ApplicationListener接口
是一个接口,里面只有一个onApplicationEvent方法。所以自己的类在实现该接口的时候,要实现该方法。
十、Enable***
- @EnableAspectJAutoProxy:开启对AspectJ自动代理的支持。
- @EnableAsync:开启异步方法支持。
- @EnableScheduling:开启计划任务
- @EnableWebMvc:开启Web Mvc配置功能