条件装配:
注解:@Condition
定义一个注解
import org.springframework.context.annotation.Conditional;import java.lang.annotation.*;/*** @author Gavin*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional(LoginFilterCondition.class)
public @interface LoginTaskConditionOnProperTy {String value();String prefix() default "";String havingValue() default "";boolean matchIfMissing() default false;boolean relaxedNames() default true;
}
配置类:
在特定条件下加载bean
这里通过配置文件(元数据) 中特定的值来实现,也可以直接在LoginFilterCondition类中添加别的逻辑
import com.hmrs.filter.LoginFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author Gavin*/
//@ConditionalOnProperty(prefix = "login", name = "enable", havingValue = "true")
@Configuration
public class LoginFilterWebConfig {/*** 注册LoginFilter* 目的:当配置文件中有元数据 login 且值为 true时 装载LoginFilter 类* @return 返回实例*/@LoginTaskConditionOnProperTy(value = "login" ,havingValue = "true")@Beanpublic LoginFilter buildFilter() {return new LoginFilter();}
}
做法—>实现Condition接口
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.MultiValueMap;import java.util.List;/*** @author Gavin*/
public class LoginFilterCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 取得指定类型注解的所有的属性MultiValueMap<String, Object> allAnnotationAttributes = metadata.getAllAnnotationAttributes(LoginTaskConditionOnProperTy.class.getName());List<Object> objectList = allAnnotationAttributes.get("value");List<Object> havingValue = allAnnotationAttributes.get("havingValue");String property = context.getEnvironment().getProperty((String) objectList.get(0));return property.equals(havingValue.get(0));}
}
配置config
import com.hmrs.filter.LoginFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author Gavin*/
//@ConditionalOnProperty(prefix = "login", name = "enable", havingValue = "true")
@Configuration
public class LoginFilterWebConfig {/*** 注册LoginFilter** @return 返回实例*/@LoginTaskConditionOnProperTy(value = "login" ,havingValue = "true")@Beanpublic LoginFilter buildFilter() {return new LoginFilter();}
}
LoginFilter类如下
import com.alibaba.fastjson2.JSONObject;
import com.hmrs.comm.BaseResult;
import com.hmrs.service.RedisRWService;
import com.hmrs.util.HmrsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author Gavin*/
@Slf4j
public class LoginFilter implements Filter {@Autowiredprivate RedisRWService redisRWService;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {if (redisRWService.hasKey("Gavin")){log.info("redis中已有key");}else{log.info("设置redis的key");redisRWService.saveObjData("Gavin", "Gavin");redisRWService.setKeyExpireTime("Gavin", 72);}}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {if (request instanceof HttpServletRequest){if (redisRWService.hasKey("Gavin")) {log.info("Gavin过滤器已生效");chain.doFilter(request, response);} else {log.info("Gavin过滤器已失效");BaseResult baseResult = HmrsUtils.setHttpBaseResult(400, "failed", "接口已失效");HmrsUtils.returnJson((HttpServletResponse) response, JSONObject.toJSONString(baseResult));return;}}else{return ;}}@Overridepublic void destroy() {}
}
在Spring Boot中,针对@Conditional做了扩展,提供了更简单的使用形式,
扩展注解如下:
ConditionalOnBean/ConditionalOnMissingBean:容器中存在某个类或者不存在某个Bean时进行Bean装载
ConditionalOnClass/ConditionalOnMissingClass:classpath下存在指定类或者不存在指定类时进行Bean装载
ConditionalOnCloudPlatform:只有运行在指定的云平台上才加载指定的Bean
ConditionalOnExpression:基于SpEl表达式的条件判断
ConditionalOnJava:只有运行指定版本的Java才会加载Bean
ConditionalOnJndi:只有指定的资源通过JNDI加载后才加载Bean
ConditionalOnWebApplication/ConditionalOnNotWebApplication:如果是Web应用或者不是Web应用,才加载指定的Bean
ConditionalOnProperty:系统中指定的对应的属性是否有对应的值
ConditionalOnResource:要加载的Bean依赖指定资源是否存在于classpath中
ConditionalOnSingleCandidate:只有在确定了给定Bean类的单个候选项时才会加载Bean
上面的代码就可以简化为:
下面一点代码:
可打断点测试
import com.hmrs.filter.LoginFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author Gavin*/
//@ConditionalOnProperty(prefix = "login", name = "enable", havingValue = "true")
@Configuration
public class LoginFilterWebConfig {/*** 注册LoginFilter** @return 返回实例*/
// @LoginTaskConditionOnProperTy(value = "login" ,havingValue = "true")//原始做法@ConditionalOnProperty(value = "login",havingValue = "true",matchIfMissing = true)@Beanpublic LoginFilter buildFilter() {return new LoginFilter();}
}
如果matchIfMissing的值为true,则没有匹配上不回加载,如果为false 则即使没有匹配上也会加载
自定义starter
基本依赖:
<dependencies><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.11.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot</artifactId><version>2.7.12</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>2.7.12</version></dependency></dependencies>
配置类:
import org.springframework.boot.context.properties.ConfigurationProperties;/*** @author Gavin* 这里的前缀即配置文件中的前缀*/
@ConfigurationProperties(prefix = "gavin.redisson")
public class RedissonProperties {private String host ="localhost";private String password ;private int port =6379;private boolean ssl;private Integer timeOut;public String getHost() {return host;}public Integer getTimeOut() {return timeOut;}public void setTimeOut(Integer timeOut) {this.timeOut = timeOut;}public void setHost(String host) {this.host = host;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getPort() {return port;}public void setPort(int port) {this.port = port;}public boolean isSsl() {return ssl;}public void setSsl(boolean ssl) {this.ssl = ssl;}
}
根据配置类创建bean
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;@Configuration
@ConditionalOnClass(Redisson.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonAutoConfiguration {@Beanpublic RedissonClient redissonClient(RedissonProperties redissonProperties) {Config config = new Config();String prefix = "redis://";if (redissonProperties.isSsl()) {prefix = "rediss://";}SingleServerConfig singleServerConfig = config.useSingleServer().setAddress(prefix + redissonProperties.getHost() + ":" + redissonProperties.getHost()).setConnectTimeout(redissonProperties.getTimeOut());if (!StringUtils.isEmpty(redissonProperties.getPassword())) {singleServerConfig.setPassword(redissonProperties.getPassword());}return Redisson.create(config);}
}
最后重要的一步:
在resources下创建META-INF/spring,factories文件,使得Spring Boot程序可以扫描到该文件完成自动装配,
#在resources下创建META-INF/spring.factories文件,使得Spring Boot程序可以扫描到该文件完成自动装配,key和value对应如下
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.gavin.RedissonAutoConfiguration
最后打包即可,然后引用该包,最后在配置文件中按需配置即可