微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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);
}

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);

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;
    }

}

resources 目录创建文件夹messages

message_en.properties

test=test

message_zh.properties

test=测试

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);

测试,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 + "]");
			}
		}
	}

使用容器中的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);
	}

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;

}

读取resources 目录下

application.properties

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

读取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);
        });

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);

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));

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);
});

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

@Autowired

defaultListablebeanfactory.getBeansOfType(BeanPostProcessor.class).values()
.stream().forEach((b) -> {
defaultListablebeanfactory.addBeanPostProcessor(b);
});

beanfactoryPostProcessor :

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

//5.通过后置处理器beanfactoryPostProcessor  处理加载bean 解析 SpringConfig 中的 配置bean
beanfactory.getBeansOfType(beanfactoryPostProcessor.class).values().stream().forEach(
    (beanfactoryPostProcessor) -> {
        beanfactoryPostProcessor.postProcessbeanfactory(beanfactory);
    }
);

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);

基于磁盘目录xml方式

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

基于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;
    }
}

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;
    }
}

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;
    }
}

@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命令");
    }
}
AnnotationConfigApplicationContext annotationConfigApplicationContext
    = new AnnotationConfigApplicationContext(SpringConditionConfig.class);
Map<String, SystemOperation> beansOfType = annotationConfigApplicationContext.getBeansOfType(SystemOperation.class);
System.out.println(beansOfType);

{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");
    }
}

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");
        }
    }

相关代码

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐