Spring重要的类和接口

一、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。
AbstractBeanDefinition上衍生出来的几个类:
  • 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 接口
具有增,查,删BeanDefinition的能力。一次只能注册一个BeanDefinition。
实现类SimpleBeanDefinitionRegistry,DefaultListableBeanFactory,GenericApplicationContext等。一般实现类里都都有一个private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap()来存储BeanDefinition。
BeanDefinitionReader接口

既可以使用BeanDefinitionRegistry构造。也可以通过loadBeanDefinitions把配置加载为多个BeanDefinition并注册到BeanDefinitionRegistry中。可以说是高效版本的BeanDefinitionRegistry。

实现类有

  • XmlBeanDefinitionReader从xml中读取BeanDefinition;
  • PropertiesBeanDefinitionReader从Properties文件读取BeanDefinition
AnnotatedBeanDefinitionReader类

对带有注解的BeanDefinition进行注册

ClassPathBeanDefinitionScanner类

可以扫描到@Component @Repository @Service @Controller 的BeanDefinition注册到容器中。

BeanDefinitionHolder
BeanDefinition包装类。

二、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方法是一个无参数的方法。

注意这个顺序:

  1. @PostConstruct注解标注的方法(JSR250)
  2. 实现InitializingBean接口的afterPropertiesSet方法(Spring的接口)
  3. 使用@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配置功能

 

posted @ 2020-11-21 22:22  codedot  阅读(1177)  评论(0编辑  收藏  举报