• 19.spring beanfactory与applicationcontext


    IOC容器架构概述

    Beanfactory和Applicacontext区别

    BeanFactory(Bean工厂)

    1.idea调试 spring源码 不需要去 spring官网下载源码 idea 支持maven jar 依赖源码

    Applicacontext BeanFactory

    2.org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) 根据名称获取单例bean对象

    3.org.springframework.context.support.AbstractApplicationContext.refresh()

    BeanFactory概述

    1.BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

    ​ 2.BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。

    ​ 3.它为其他具体的IOC容器提供了最基本的规范,例如DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。

    ​ 4.原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来。现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。

    ​ 5.BeanFactory实际上是实例化,配置和管理众多bean的容器。 这些bean通常会彼此合作,因而它们之间会产生依赖。 BeanFactory使用的配置数据可以反映这些依赖关系中,一个BeanFactory可以用接口org.springframework.beans.factory.BeanFactory表示, 这个接口有多个实现。 最常使用的的简单的BeanFactory实现是org.springframework.beans.factory.xml.XmlBeanFactory。

    按住键盘ctrl+alt+u生成类图

    img

    Applicacontext间接的形式继承Beanfactory 实现额外功能扩展 保留了Beanfactory 基础功能

    例如getBean()

    AnnotationConfigApplicationContext applicationContext
    = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserEntity userEntity = applicationContext.getBean("user", UserEntity.class);
    #####查看底层源码 底层通过getBeanFactory().getBean方法
    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    		assertBeanFactoryActive();
    		return getBeanFactory().getBean(name, requiredType);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    BeanFactory核心功能

    BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用

    通过类图可以分析出:DefaultSingletonBeanRegistry 负责管理单例对象 底层采用

    public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    
    	/** Cache of singleton objects: bean name to bean instance. */
    	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    • 1
    • 2
    • 3
    • 4

    Applicacontext功能

    ApplicationContext的中文意思是“应用前后关系”,它继承自BeanFactory接口,除了包含BeanFactory的所有功能之外,在国际化支持、资源访问(如URL和文件)、事件传播等方面进行了良好的支持,被推荐为Java EE应用之首选,可应用在Java APP与Java Web中。

    img

    1.MessageSource(国际化的支持)

    2.ResourcePatternResolver (匹配资源路径)

    3.EnvironmentCapable (环境变量配置)

    4.ApplicationEventPublisher(事件发布)

    MessageSource(国际化的支持)

    MessageSource基本用法

    messageSource是spring中的转换消息接口,提供了国际化信息的能力。MessageSource用于解析消息,并支持消息的参数化和国际化。 Spring 包含两个内置的MessageSource实现:ResourceBundleMessageSource和ReloadableResourceBundleMessageSource。

    package com.mayikt.config;
    
    import com.mayikt.entity.UserEntity;
    import com.mayikt.service.MayiktService;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.support.ResourceBundleMessageSource;
    
    
    @Configuration
    @ComponentScan(value = {"com.mayikt.service"})
    public class SpringConfig {
     
        @Bean
        public ResourceBundleMessageSource messageSource() {
            ResourceBundleMessageSource source = new ResourceBundleMessageSource();
            //设置基础名
            source.setBasenames("messages/message");
            //设置编码
            source.setDefaultEncoding("GBK");
            return source;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    resources 目录创建文件夹messages

    message_en.properties

    test=test
    
    • 1

    message_zh.properties

    test=测试
    
    • 1

    img

    AnnotationConfigApplicationContext applicationContext
        = new AnnotationConfigApplicationContext(SpringConfig.class);
    ResourceBundleMessageSource messageSource =
        applicationContext.getBean("messageSource", ResourceBundleMessageSource.class);
    String test1 = messageSource.getMessage("test", null, Locale.CHINESE);
    String test2 = messageSource.getMessage("test", null, Locale.ENGLISH);
    System.out.println(test1 + "," + test2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试,test

    MessageSource底层实现

    spring的AbstractApplicationContext中MessageSource初始化

    初始化

    在AbstractApplicationContext中有一个refresh()方法,在刷新方法里面调用一个initMessageSource()。initMessageSource()方法就是初始化上下文中的MessageSource资源国际化组件。

    protected void initMessageSource() {
    		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
    			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
    			// Make MessageSource aware of parent MessageSource.
    			if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
    				HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
    				if (hms.getParentMessageSource() == null) {
    					// Only set parent context as parent MessageSource if no parent MessageSource
    					// registered already.
    					hms.setParentMessageSource(getInternalParentMessageSource());
    				}
    			}
    			if (logger.isTraceEnabled()) {
    				logger.trace("Using MessageSource [" + this.messageSource + "]");
    			}
    		}
    		else {
    			// Use empty MessageSource to be able to accept getMessage calls.
    			DelegatingMessageSource dms = new DelegatingMessageSource();
    			dms.setParentMessageSource(getInternalParentMessageSource());
    			this.messageSource = dms;
    			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    使用容器中的messageSource

    AbstractApplicationContext提供了接口getMessage方法来使用容器中的messagesource

    	@Override
    	public String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) {
    		return getMessageSource().getMessage(code, args, defaultMessage, locale);
    	}
    
    • 1
    • 2
    • 3
    • 4

    ResourcePatternResolver (匹配资源路径)

    用于解析资源文件的策略接口,其特殊的地方在于,它应该提供带有*号这种通配符的资源路径。

    此接口是ResourceLoader接口的拓展接口。

    PathMatchingResourcePatternResolver是此接口的独立实现,其常常用于应用上下文之外如ResourceArrayPropertyEditor中

    理应支持所有类似”/WEB-INF/*-context.xml”这种模式的路径输入

    在写一个资源路径时,提倡使用classpath*作为前缀以查找所有Jar的根目录。使用无占位符的

    文件名如/beans.xml来确切的表名想要引入的文件名。

    package org.springframework.core.io.support;
    
    import java.io.IOException;
    
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.ResourceLoader;
    
    public interface ResourcePatternResolver extends ResourceLoader {
    
    	 /**
         * 在所有根目录下搜索文件的伪URL的前缀
         * 与ResourceLoader中classpath不同的地方在于,此前缀会在所有的JAR包的根目录下搜索指定文件。
         */
    	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
    
       /**
         * 返回指定路径下所有的资源对象。
         * 返回的对象集合应该有Set的语义,也就是说,对于同一个资源,只应该返回一个资源对象
         */
    	Resource[] getResources(String locationPattern) throws IOException;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    读取resources 目录下

    application.properties

    name=mayikt
            Resource[] resources = applicationContext.getResources("classpath:application.properties");
            Arrays.stream(resources).forEach((r) -> {
                System.out.println(r);
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    读取spring-beans-5.2.1.RELEASE.jar!/META-INF/spring.factories

            Resource[] resources = applicationContext.getResources("classpath*:META-INF/spring.factories");
            Arrays.stream(resources).forEach((r) -> {
                System.out.println(r);
            });
    
    • 1
    • 2
    • 3
    • 4

    img

    classpath: 只会到你的target下面的class路径中查找找文件

    classpath*:(1)不仅包含target下面的class路径,还包括jar文件中(target下面的class路径)进行查找;(2)当项目中有多个classpath路径(不是xml文件,而是包含xml文件的路径),并同时加载多个classpath路径下的所有xml文件,就发挥了作用,如果不加*,也就是只使用classpath,则表示仅仅加载匹配到的第一个classpath路径

    EnvironmentCapable (环境变量配置)

    读取:

    1.JAVA 系统变量 java -D命令后的配置

    2.操作系统环境变量

    3.application.yml,application.properties文件

    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    String javaHome = environment.getProperty("java_home");
    String comMayikt = environment.getProperty("com.mayikt");
    System.out.println(javaHome +  "," + comMayikt);
    
    • 1
    • 2
    • 3
    • 4

    img

    -Dcom.mayikt=mayikt.com

    ApplicationEventPublisher(事件发布)

    1.ApplicationEventPublisherAware

    ApplicationEventPublisherAware 是由 Spring 提供的用于为 Service 注入 ApplicationEventPublisher 事件发布器的接口,使用这个接口,我们自己的 Service 就拥有了发布事件的能力。

    用户注册后,不再是显示地调用其他的业务 Service,而是发布一个用户注册事件。

    2.ApplicationListener

    ApplicationListener接口是由 Spring 提供的事件订阅者必须实现的接口,我们一般把该 Service 关心的事件类型作为泛型传入。处理事件,通过 event.getSource() 即可拿到事件的具体内容

    3.ApplicationEventPublisher

    ApplicationEventPublisher是ApplicationContext的父接口之一。这接口的作用是:Interface that encapsulates event publication functionality.

    功能就是发布事件,也就是把某个事件告诉的所有与这个事件相关的监听器。

    public class UserInfoEvent extends ApplicationEvent {
        /**
         * source事件源
         *
         * @param source
         */
        public UserInfoEvent(Object source) {
            super(source);
        }
    }
    
    @Component
    public class EmailListener {
        private static final Logger log = LoggerFactory.getLogger(EmailListener.class);
    
        @EventListener
        public void emailListener(UserInfoEvent userInfoEvent) {
            log.debug("userInfoEvent:{}", userInfoEvent);
        }
    }
    @Component
    public class PhoneListener  {
        private static final Logger log = LoggerFactory.getLogger(PhoneListener.class);
    
        @EventListener
        public void emailListener(UserInfoEvent userInfoEvent) {
            log.debug("userInfoEvent:{}", userInfoEvent);
        }
    
    }
    AnnotationConfigApplicationContext applicationContext
                    = new AnnotationConfigApplicationContext(SpringConfig.class);
    applicationContext.publishEvent(new UserInfoEvent(applicationContext));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    Beanfactory功能

    1.BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

    2.BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。

    ​ 3.它为其他具体的IOC容器提供了最基本的规范,例如DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。

    ​ \3. 原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来。现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。

    ​ 4.BeanFactory实际上是实例化,配置和管理众多bean的容器。 这些bean通常会彼此合作,因而它们之间会产生依赖。 BeanFactory使用的配置数据可以反映这些依赖关系中,一个BeanFactory可以用接口org.springframework.beans.factory.BeanFactory表示, 这个接口有多个实现。 最常使用的的简单的BeanFactory实现是org.springframework.beans.factory.xml.XmlBeanFactory。

    Beanfactory后置处理器

    ApplicationContext 属于实现方式 AnnotationConfigApplicationContext(注解启动方式)

    AnnotationConfigApplicationContext----继承父类AbstractApplicationContext…

    refresh()------先创建一个默认的DefaultListableBeanFactory

    1.后置处理(加载bean 、依赖注入)

    2.初始化国家化配置、事件监听

    ConfigurationClassPostProcessor 解析Configuration配置 bean注解 并且加载到ioc容器中

    DefaultListableBeanFactory是整个bean加载的核心,是spring注册及加载bean的默认实现。

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor ##
    处理lConfiguration注解

    org.springframework.context.annotation.internalAutowiredAnnotationProcessor ##处理Autowired

    org.springframework.context.annotation.internalCommonAnnotationProcessor ##处理@Resource

    //1.获取beanFactory
    DefaultListableBeanFactory beanFactory
        = new DefaultListableBeanFactory();
    //2.bean 定义 class(反射初始化)、是否是为单例 销毁
    AbstractBeanDefinition beanDefinition
        = BeanDefinitionBuilder.genericBeanDefinition
        (SpringConfig.class).getBeanDefinition();
    //3.注册beanDefinition
    beanFactory.registerBeanDefinition("springConfig", beanDefinition);
    //4.新增我们的后置处理器 解析配置
    AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
    //5.通过后置处理器BeanFactoryPostProcessor  处理加载bean 解析 SpringConfig 中的 配置bean
    beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(
        (beanFactoryPostProcessor) -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    );
    //6.处理依赖注入@Autowired
    beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().forEach(
        (beanPostProcessor) -> {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    );
    // 7.提前初始化单例对象
    beanFactory.preInstantiateSingletons();
    System.out.println("------------");
    // 默认的情况下延迟加载 可以采用
    MayiktBean mayiktBean = beanFactory.getBean("mayiktBean", MayiktBean.class);
    System.out.println(mayiktBean.getUserEntity());
    
    //8.输出beanName
    Arrays.stream(beanFactory.getBeanDefinitionNames()).forEach((beanName) -> {
        System.out.println("beanName:" + beanName);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    BeanPostProcessor:该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的

    @Autowired

    defaultListableBeanFactory.getBeansOfType(BeanPostProcessor.class).values()
    .stream().forEach((b) -> {
    defaultListableBeanFactory.addBeanPostProcessor(b);
    });
    
    • 1
    • 2
    • 3
    • 4

    BeanFactoryPostProcessor :

    BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等,很多框架都是通过此接口实现对spring容器的扩展

    //5.通过后置处理器BeanFactoryPostProcessor  处理加载bean 解析 SpringConfig 中的 配置bean
    beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(
        (beanFactoryPostProcessor) -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    BeanFactory 不会主动调用BeanFactory后置处理器 和Bean后置处理器、提前初始化单例, 而我们Applicacontext封装BeanFactory 实现好了 根据后置处理器 bean对象初始化。

    Bean后置处理器 bean初始化 、依赖注入

    下次课----后置处理器 bean生命周期中

    Applicacontext实现

    1.基于xml方式

    2.基于磁盘目录xml方式

    3.基于java配置类方式

    4.web环境 java配置类方式 AnnotationConfigWebApplicationContext

    基于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="userEntity" class="com.mayikt.entity.UserEntity">
        </bean>
    </beans>
            //1.基于xml
            ClassPathXmlApplicationContext classPathXmlApplicationContext
                    = new ClassPathXmlApplicationContext("spring-bean.xml");
            UserEntity userEntity = classPathXmlApplicationContext.getBean("userEntity", UserEntity.class);
            System.out.println(userEntity);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    基于磁盘目录xml方式

    FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("D:\\list\\spring-bean.xml");
    UserEntity userEntity = fileSystemXmlApplicationContext.getBean("userEntity", UserEntity.class);
    System.out.println(userEntity);
    
    • 1
    • 2
    • 3

    基于java配置类方式

    1.配置类@Configuration

    2.@ComponentScan 组件使用(@Controller/@Service/@Reponsitory/@Component)

    3.使用@Bean注解配置类中的方法

    4.@Import 快速给容器中导入组件

    id默认为组件的全类名

    三种方式:

    4.1@Import({A.class,B.class}) 组件的id默认是全类名

    4.2@Import (MyImportSelector.class)

    其中MyImportSelector实现了ImportSelector接口

    4.2@Import (MyImportSelector.class)

    其中MyImportSelector实现了ImportBeanDefinitionRegistrar接口

    5.@Scope 设置组件作用域

    singleton:单实例(默认) --ioc容器启动时会调用相关方法创建对象并放到ioc容器中

    prototype:多实例 --每次获取Bean的时候才会调用相关方法创建对象

    request:同一次请求创建一个实例

    session:同一个session创建一个实例

    6.@Lazy 懒加载:针对单实例Bean

    容器启动的时候先不创建对象,在第一次获取Bean的时候创建对象并初始化

    7.@Conditional 按照一定的条件来决定Bean是否加载到IOC容器中 可以注解类和方法,需要传入Class数组,对应的类要实现Condition接口。

    @Import

    1.@Import 直接导入配置类

    package com.mayikt.config;
    
    import org.springframework.context.annotation.Bean;
    
    
    public class Spring03Config {
        @Bean
        public MayiktBean mayiktBean() {
            return new MayiktBean();
        }
    }
    
    package com.mayikt.config;
    
    import com.mayikt.entity.UserEntity;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    
    @Configuration
    @ComponentScan("com.mayikt.service")
    @Import({Spring03Config.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class Spring02Config {
        @Bean
        public UserEntity user() {
            UserEntity userEntity = new UserEntity();
            return userEntity;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2.@Import 直接导入配置类

    其中MyImportSelector实现了ImportSelector接口

    package com.mayikt.config;
    
    import org.springframework.context.annotation.ImportSelector;
    import org.springframework.core.type.AnnotationMetadata;
    
    
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{"com.mayikt.config.Spring04Config"};
        }
    }
    
    package com.mayikt.config;
    
    import org.springframework.context.annotation.Bean;
    
    
    public class Spring04Config {
        @Bean
        public MayiktBean mayiktBean02() {
            return new MayiktBean();
        }
    }
    
    
    package com.mayikt.config;
    
    import com.mayikt.entity.UserEntity;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    
    @Configuration
    @ComponentScan("com.mayikt.service")
    @Import({Spring03Config.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class Spring02Config {
        @Bean
        public UserEntity user() {
            UserEntity userEntity = new UserEntity();
            return userEntity;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    3实现ImportBeanDefinitionRegistrar接口

    package com.mayikt.config;
    
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
    import org.springframework.core.type.AnnotationMetadata;
    
    
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(MayiktBean.class);
            registry.registerBeanDefinition("mayiktBean03", rootBeanDefinition);
        }
    }
    package com.mayikt.config;
    
    import com.mayikt.entity.UserEntity;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    
    @Configuration
    @ComponentScan("com.mayikt.service")
    @Import({Spring03Config.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class Spring02Config {
        @Bean
        public UserEntity user() {
            UserEntity userEntity = new UserEntity();
            return userEntity;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    @Conditional

    @Conditional 翻译过来就是:条件装配

    就是指满足指定的条件,则进行组件注入,如果不满足,则不注入

    以下为springboot的封装

    @ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。

    @ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean。

    @ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean。

    @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean。

    @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean。

    @ConditionalOnNotWebApplication:不是web应用,才会实例化一个Bean。

    @ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。

    @ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。

    @ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。

    @ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。

    @ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。

    @ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。

    @ConditionalOnProperty:当指定的属性有指定的值时进行实例化。

    @ConditionalOnExpression:基于SpEL表达式的条件判断。

    @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。

    @ConditionalOnResource:当类路径下有指定的资源时触发实例化。

    @ConditionalOnJndi:在JNDI存在的条件下触发实例化。

    @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。

    案例1 不同环境执行不同操作

    package com.mayikt.condition;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class LinuxCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            return System.getProperty("os.name").toLowerCase().contains("linux");
        }
    }
    package com.mayikt.condition;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class WindowsCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            return System.getProperty("os.name").toLowerCase().contains("windows");
        }
    }
    
    package com.mayikt.condition;
    
    public class SystemOperation {
        private String name;
    
        public SystemOperation(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "SystemOperation{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    package com.mayikt.condition;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class SpringConditionConfig {
    
        @Bean
        @Conditional(value = WindowsCondition.class)
        public SystemOperation windowsSystemOperation() {
            return new SystemOperation("执行windows命令");
        }
    
        @Bean
        @Conditional(value = LinuxCondition.class)
        public SystemOperation linuxSystemOperation() {
            return new SystemOperation("执行linux命令");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    AnnotationConfigApplicationContext annotationConfigApplicationContext
        = new AnnotationConfigApplicationContext(SpringConditionConfig.class);
    Map<String, SystemOperation> beansOfType = annotationConfigApplicationContext.getBeansOfType(SystemOperation.class);
    System.out.println(beansOfType);
    
    • 1
    • 2
    • 3
    • 4

    {windowsSystemOperation=SystemOperation{name=‘执行windows命令’}}

    案例2 判断如果有该类的话 则直接报错

    package com.mayikt.config;
    
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    @Configuration
    public class SpringConditionalOnClass {
    
        @Bean
        @ConditionalOnClass(name = "com.mayikt.config.MayiktConfig")
        public Object object1() throws Exception {
            throw new Exception("当前环境中中不允许MayiktConfig");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Spring Cloud Gateway 启动报错(因为web依赖) 报错:

    Spring Cloud Gateway启动一直报错 详细错误信息

    Parameter 0 of method modifyRequestBodyGatewayFilterFactory in org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type ‘org.springframework.http.codec.ServerCodecConfigurer’ that could not be found.

    Action:

    Consider defining a bean of type ‘org.springframework.http.codec.ServerCodecConfigurer’ in your configuration.

       @Configuration(
            proxyBeanMethods = false
        )
        @ConditionalOnMissingClass({"org.springframework.web.reactive.DispatcherHandler"}) //重点注解
        protected static class WebfluxMissingFromClasspathConfiguration {
            public WebfluxMissingFromClasspathConfiguration() {
                GatewayClassPathWarningAutoConfiguration.log.warn("\n\n**********************************************************\n\nSpring Webflux is missing from the classpath, which is required for Spring Cloud Gateway at this time. Please add spring-boot-starter-webflux dependency.\n\n**********************************************************\n\n");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    相关代码

    📎2022年8月13日–spring源码解读.rar

  • 相关阅读:
    C++ 资源大全:标准库、Web框架、人工智能等 | 最全整理
    Mysql基础 (二)
    大学生个人网页模板 简单网页制作作业成品 极简风格个人介绍HTML网页设计代码下载
    Mybatis入门
    shell指令练习
    【BLE】蓝牙Profile
    java计算机毕业设计ssm+vue工商学院办公用品管理信息系统
    切片有哪些注意事项是一定要知道的呢
    Model/ModelAndView
    OOM排查
  • 原文地址:https://blog.csdn.net/u014001523/article/details/126512697