2022-01-25 Spring控制是否初始化Bean

背景

本次因为业务要求需要集成外部jar,但是该jdk版本是1.8,我们的服务是当前使用区域支持1.8但是其他其余部分不支持,但是也不需要该服务。因此需要项目差异化实例化需要调用的服务

实现方式

  • 引入第三方jar,并且设置访问provided
    scope的其他参数如下:
    compile
    默认的scope,表示 dependency 都可以在生命周期中使用。而且,这些dependencies 会传递到依赖的项目中。适用于所有阶段,会随着项目一起发布
    provided
    跟compile相似,但是表明了dependency 由JDK或者容器提供,例如Servlet AP和一些Java EE APIs。这个scope 只能作用在编译和测试时,同时没有传递性。
    采用provided的好处就是保证了该jar方法可以正常使用以及编译,但是不会发布;
  • 在区域差异化打包中重新引入该jar的maven信息
  • 最后控制引用该方法的实例方法是否被初始化

Profile

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({ProfileCondition.class})
public @interface Profile {
    String[] value();
}

@Component
@Profile("dev")
public class DevDatasourceConfig

上面的DevDatasourceConfig被定义为 profile=dev,于是该Bean只会在dev(开发环境)模式下被启用。
如果需要定义为非dev环境,可以使用这样的形式:

@Component
@Profile("!dev")
public class DevDatasourceConfig

设置Profile的方式

  • WebApplicationInitializer接口
@Configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.setInitParameter("spring.profiles.active", "dev");
    }
}
  • JVM启动参数
    -Dspring.profiles.active=dev
  • 通过 web.xml定义
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>
  • application.properties
    可以在application.properties配置文件中指定spring.profiles.active属性:
spring.profiles.active=dev
  • Maven Profile
<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <spring.profiles.active>dev</spring.profiles.active>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <spring.profiles.active>prod</spring.profiles.active>
        </properties>
    </profile>
</profiles>

源码分析

@Profile实际上是一个@Conditional注解。并且明确使用了ProfileCondition

class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if (attrs != null) {
			for (Object value : attrs.get("value")) {
				if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
					return true;
				}
			}
			return false;
		}
		return true;
	}
}

mathces()方法的返回值是一个布尔值,返回true时,spring就会创建这个bean,返回false时就不会创建。

@Condition解析

@ConditionalOnBean 当容器有指定Bean的条件下
@ConditionalOnClass 当容器有指定类的条件下
@ConditionalOnExpression 基于SpEL表达式作为判断条件
@ConditionalOnJava 基于JVM版本作为判断条件
@ConditionalOnJndi 在JDNI存在的条件下查找指定位置
@ConditionalOnMissingBean 当容器没有指定Bean的情况下
@ConditionalOnMissingClass 当容器没有指定类的情况下
@ConditionalOnNotWebApplication 当前项目不是Web项目的条件下
@ConditionalOnProperty 指定的属性是否有指定的值
@ConditionalOnResource 类路径是否有指定的值
@ConditionalOnSingleCandidate 当前指定Bean在容器中只有一个,或者虽然有多个但是指定首选Bean
@ConditionalOnWebApplication 当前项目是Web项目的情况下

@FunctionalInterface
public interface Condition {
	/**
	 * Determine if the condition matches.
	 * @param context the condition context
	 * @param metadata the metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
	 * or {@link org.springframework.core.type.MethodMetadata method} being checked
	 * @return {@code true} if the condition matches and the component can be registered,
	 * or {@code false} to veto the annotated component's registration
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}
	//获取ioc使用的beanFactory
	ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
	//获取类加载器
	ClassLoader classLoader = conditionContext.getClassLoader();
	//获取当前环境信息
	Environment environment = conditionContext.getEnvironment();
	//获取bean定义的注册类
	BeanDefinitionRegistry registry = conditionContext.getRegistry();

实际项目中可以自定义注解并且继承Condition,用于认为判断是否需要实例化该bean

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值