zoukankan      html  css  js  c++  java
  • 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配置功能
  • 相关阅读:
    vmareworkstation 15 安装密钥
    Linux进入ftp界面退出方法
    linux安装mysql(5.1.73)
    安装http服务,用http搭建web网
    telnet远程连接
    yum出现问题解决方法
    samba
    nfs搭建
    解决VMwareworkstation无法在windows上运行
    2 shell编程
  • 原文地址:https://www.cnblogs.com/myitnews/p/14017642.html
Copyright © 2011-2022 走看看