META-INF/spring.factories
spring提供的starter
spring-boot-starter-web
spring-boot-starter-freemarker
spring-boot-starter-data-redis
第三方的starter
mybatis-spring-boot-starter
1. 创建项目, 定义bean
2. 创建AutoConfiguration, @Bean实例化上面的bean
3. 定义注解,@Import(xxxAutoConfiguration.class) //引入xxxAutoConfiguration配置类
4. demo项目引入 starter项目, maven引入 spring-boot-configuration-processor
5. 打包
--创建项目, 定义bean
public class LogFilterRegistrationBean extends FilterRegistrationBean {
public LogFilterRegistrationBean() {
super();
this.setFilter(new LogFilter()); //添加LogFilter过滤器
this.addUrlPatterns("/*"); // 匹配所有路径
this.setName("LogFilter"); // 定义过滤器名
this.setOrder(1); // 设置优先级
}
}
public class LogFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(LogFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("-----logFilter init...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 从request中获取到访问的地址,并在控制台中打印出来
HttpServletRequest request = (HttpServletRequest) servletRequest;
logger.info("-----uri {} is working.", request.getRequestURI());
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
logger.info("-----logFilter destroy...");
}
}
--创建AutoConfiguration, @Bean实例化上面的bean
/**
*
* @author kevin
*
*/
@Configuration
@ConditionalOnClass({LogFilterRegistrationBean.class, LogFilter.class})
public class LogFilterAutoConfiguration {
@Bean
@ConditionalOnMissingBean(LogFilterRegistrationBean.class)
public LogFilterRegistrationBean logFilterRegistrationBean() {
return new LogFilterRegistrationBean();
}
}
--定义注解,@Import(xxxAutoConfiguration.class) //引入xxxAutoConfiguration配置类
/**
*
* @author kevin
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(LogFilterAutoConfiguration.class) //引入LogFilterAutoConfiguration配置类
public @interface EnableLogFilter {
}
--demo项目引入 starter项目, maven引入 spring-boot-configuration-processor
org.springframework.boot
spring-boot-configuration-processor
true
com.kevin
springboot-log-starter
0.0.1-SNAPSHOT
@SpringBootApplication
@RestController
@EnableLogFilter
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
@GetMapping("/test")
public String test() {
return "this is a demo boot.";
}
}
--打包
pom加入配置
META-INF
META-INF/
测试
http://localhost:8080/test
/**
*
* @author kevin
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//@Import(LogFilterAutoConfiguration.class) //引入LogFilterAutoConfiguration配置类
@Import(EnableLogFilterImportSelector.class) //引入通用批量加载
public @interface EnableLogFilter {
}
下面这个类通用
/**
*
* @author kevin
*
*/
public class EnableLogFilterImportSelector implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {
private static final Logger logger = LoggerFactory.getLogger(EnableLogFilterImportSelector.class);
private ClassLoader beanClassLoader;
private Class annotationClass = EnableLogFilter.class;
private Environment environment;
@Override
public String[] selectImports(AnnotationMetadata metadata) {
// 是否生效,默认为true
if (!isEnabled()) {
return new String[0];
}
// 获取注解中的属性
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
Assert.notNull(attributes, "No " + getSimpleName() + " attributes found. Is " + metadata.getClassName()
+ " annotated with @" + getSimpleName() + "?");
// 从spring.factories中获取所有通过EnableLogFilter注解引入的自动配置类,并进行去重操作
List factories = new ArrayList<>(new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
if (factories.isEmpty() && !hasDefaultFactory()) {
throw new IllegalStateException("Annotation @" + getSimpleName()
+ " found, but there are no implementations. Did you forget to include a starter?");
}
if (factories.size() > 1) {
logger.warn("More than one implementation " + "of @" + getSimpleName()
+ " (now relying on @Conditionals to pick one): " + factories);
}
return factories.toArray(new String[factories.size()]);
}
protected boolean hasDefaultFactory() {
return false;
}
protected boolean isEnabled() {
return true;
}
;
protected String getSimpleName() {
return this.annotationClass.getSimpleName();
}
protected Class getAnnotationClass() {
return this.annotationClass;
}
protected Environment getEnvironment() {
return this.environment;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
}
List
SpringFactoriesLoader.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
看这句
SpringFactoriesLoader .java
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
测试如常.