-
2019-02-01 14:42:32
1 定义EnableScanner注解,作用是对指定的packages文件夹下的类进行特殊处理,比如设置特殊值等!
package com.cyb.myenable; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(ScannerPackageRegistrar.class) public @interface EnableScanner { String[] packages(); }
2 定义注解引入的执行类,并将其注册到spring容器中
package com.cyb.myenable; import java.util.Arrays; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** *作者 : iechenyb<br> *类描述: 说点啥<br> *创建时间: 2019年2月1日 */ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; public class ScannerPackageRegistrar implements ImportBeanDefinitionRegistrar { Log log = LogFactory.getLog(ScannerPackageRegistrar.class); public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { System.out.println( "packages value::" + annotationMetadata.getAnnotationAttributes(EnableScanner.class.getName())); String[] arrs = (String[]) annotationMetadata.getAnnotationAttributes(EnableScanner.class.getName()) .get("packages"); List<String> packages = Arrays.asList(arrs); System.out.println(packages); BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(MyBeanDefinitionProcessor.class); bdb.addPropertyValue("packages", packages); beanDefinitionRegistry.registerBeanDefinition(MyBeanDefinitionProcessor.class.getName(), bdb.getBeanDefinition()); } }
3 定义bean前后置处理器,对指定包里的类进行特殊的初始化。
package com.cyb.myenable; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** *作者 : iechenyb<br> *类描述: 所有的bean定义时添加前后处理逻辑<br> *创建时间: 2019年2月1日 */ public class MyBeanDefinitionProcessor implements BeanPostProcessor{ Log log = LogFactory.getLog(MyBeanDefinitionProcessor.class); private List<String> packages; public List<String> getPackages() { return packages; } public void setPackages(List<String> packages) { this.packages = packages; } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { for (String pkg : packages) { if(bean.getClass().getName().startsWith(pkg)){ System.out.println("instance bean:"+bean.getClass().getName()); } } return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
4 定义配置类,启动注解
package com.cyb.myenable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.annotation.Configuration; /** *作者 : iechenyb<br> *类描述: 说点啥<br> *创建时间: 2019年2月1日 */ @Configuration @EnableScanner(packages={"com.cyb.adapter","com.cyb.advice"}) public class ScannerConfiguration { Log log = LogFactory.getLog(ScannerConfiguration.class); }
更多相关内容 -
Spring 自定义Enable注解以及Enable注解扩展
2020-03-26 14:55:17在我们日常开发中,经常使用Enable注解来开启某些功能。例如 EnableDiscoveryClient EnableFeignClients @EnableAuthorizationServer .... 我们发现这些注解都是用来开启某些功能的,其实如果...在我们日常开发中,经常使用Enable注解来开启某些功能。例如
-
EnableDiscoveryClient
-
EnableFeignClients
-
@EnableAuthorizationServer
- ....
我们发现这些注解都是用来开启某些功能的,其实如果我们换句话来说可能更好理解,就是用来加载某些配置的。
那么我们来自定义一个Enable注解,首先我们需要对注解有一定的了解,下面是我摘抄的网上的一段说明。
01) @interface
使用 @interface 定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个Annotation。
定义 Annotation 时,@interface 是必须的。
注意:它和我们通常的 implemented 实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。
(02) @Documented
类和方法的 Annotation 在缺省情况下是不出现在 javadoc 中的。如果使用 @Documented 修饰该 Annotation,则表示它可以出现在 javadoc 中。
定义 Annotation 时,@Documented 可有可无;若没有定义,则 Annotation 不会出现在 javadoc 中。
(03) @Target(ElementType.TYPE)
前面我们说过,ElementType 是 Annotation 的类型属性。而 @Target 的作用,就是来指定 Annotation 的类型属性。
@Target(ElementType.TYPE) 的意思就是指定该 Annotation 的类型是 ElementType.TYPE。这就意味着,MyAnnotation1 是来修饰"类、接口(包括注释类型)或枚举声明"的注解。
定义 Annotation 时,@Target 可有可无。若有 @Target,则该 Annotation 只能用于它所指定的地方;若没有 @Target,则该 Annotation 可以用于任何地方。
(04) @Retention(RetentionPolicy.RUNTIME)
前面我们说过,RetentionPolicy 是 Annotation 的策略属性,而 @Retention 的作用,就是指定 Annotation 的策略属性。
@Retention(RetentionPolicy.RUNTIME) 的意思就是指定该 Annotation 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将该 Annotation 信息保留在 .class 文件中,并且能被虚拟机读取。
定义 Annotation 时,@Retention 可有可无。若没有 @Retention,则默认是 RetentionPolicy.CLASS。
下面我们说了怎么自定义一个Enable注解,其实Enable的方式有很多种。
我们先介绍最简单的一种,直接引入:
/** * 开启天润外呼 * @author clark */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Import(TRCallConfig.class) public @interface EnableTRCall { }
引入配置类
/** * 天润外呼配置类 * @author clark */ @EnableConfigurationProperties({ TRCallProperties.class}) public class TRCallConfig { @Autowired private TRCallProperties trCallProperties; /** * 实例化天润外呼业务 * @return */ @Bean("trCallService") CallService trCallService(){ TRCallServiceImpl trCallService = new TRCallServiceImpl(); trCallService.setTrCallProperties(trCallProperties); return trCallService; } }
那么这样我们就实现了一个自定义的Eable注解了,当然这是比较简单的。
下面我们来说下第二种,根据参数加载不同的配置类的方法。
/** * 全局开启外呼注解:与单个开启等价 * @author clark */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Import(CallConfigurationSelector.class) public @interface EnableCall { /** * 开启类型 * @return */ String[] type(); }
/** * 配置加载 * @author clark */ public class CallConfigurationSelector implements ImportSelector{ /** * 解析type参数,动态加载配置类 * @param annotationMetadata * @return */ @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { //获取注解的属性集合 AnnotationAttributes attributes = AnnotationAttributes.fromMap( annotationMetadata.getAnnotationAttributes(EnableCall.class.getName(), false)); //设置type String[] types = attributes.getStringArray("type"); if(types==null||types.length==0){ throw new IllegalStateException("type is required"); } List<String> results = new ArrayList<>(); //处理类型 for(String type : types) { CallType callType = CallType.valueOf(type); switch (callType) { case CDR: results.add(CDRCallConfig.class.getName()); break; case TKY: results.add(TKYCallConfig.class.getName()); break; case TR: results.add(TRCallConfig.class.getName()); break; case ZC: results.add(ZCCallConfig.class.getName()); break; default: throw new IllegalStateException("no type is matching"); } } return results.toArray(new String[results.size()]); } }
对于Import能引入的类型,我们可以参考源码进行查看。
-
-
springboot 自定义Enable* 注解
2018-10-18 10:00:531.定义一个注解类 EnableScanner package com.boot.condition.bootcondition.simple; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure....项目结构:
1.定义一个注解类 EnableScanner
package com.boot.condition.bootcondition.simple; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; /** * 〈一句话功能简述〉<br> * 〈扫描包〉 * * @author 26918 * @create 2018/10/17 * @since 1.0.0 */ @SpringBootApplication @EnableScanner(packages = {"com.boot.condition.bootcondition.simple.entity", "com.boot.condition.bootcondition.simple.bean"}) public class ScannerPackageApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(ScannerPackageApplication.class, args); context.close(); } } import org.springframework.context.annotation.Import; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(ScannerPackageRegistrar.class) public @interface EnableScanner { String[] packages(); }
2.导入需要扫描的注册类 ScannerPackageRegistrar, 将扫描的对象设置到spring容器
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 〈一句话功能简述〉<br> * 〈〉 * * @author 26918 * @create 2018/10/17 * @since 1.0.0 */ public class ScannerPackageRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { System.out.println("packages value::"+annotationMetadata.getAnnotationAttributes(EnableScanner.class.getName())); String[] arrs = (String[]) annotationMetadata.getAnnotationAttributes(EnableScanner.class.getName()).get("packages"); List<String> packages = Arrays.asList(arrs); System.out.println(packages); BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(MyBeanDefinitionProcessor.class); bdb.addPropertyValue("packages", packages); beanDefinitionRegistry.registerBeanDefinition(MyBeanDefinitionProcessor.class.getName(), bdb.getBeanDefinition()); } }
3.定义一个MyBeanDefinitionProcessor implements BeanPostProcessor 用于初始回调对象
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; import java.util.List; /** * 〈一句话功能简述〉<br> * 〈bean 初始回调〉 * * @author 26918 * @create 2018/10/17 * @since 1.0.0 */ public class MyBeanDefinitionProcessor implements BeanPostProcessor { private List<String> packages; public List<String> getPackages() { return packages; } public void setPackages(List<String> packages) { this.packages = packages; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { for (String pkg : packages) { if(bean.getClass().getName().startsWith(pkg)){ System.out.println("instance bean:"+bean.getClass().getName()); } } return bean; } }
-
自定义@EnableXXX注解
2021-11-04 17:10:15自定义@EnableXXX注解 场景 自定义注解 + AOP 实现接口日志的自动记录(日志记录器),将本项目打包到别的项目上使用时,一开始没有效果,后来发现是因为SpringBoot项目默认注册主程序所在包以及子包的Bean , 而导入...自定义@EnableXXX注解
场景
自定义注解 + AOP 实现接口日志的自动记录(日志记录器),将本项目打包到别的项目上使用时,一开始没有效果,后来发现是因为SpringBoot项目默认注册主程序所在包以及子包的Bean , 而导入的日志记录器里面的所有Bean都没有注入Spring IOC容器 , 所以在主程序上使用@ComponentScan(basePackages = {“com.lian.song”}) 注解,显式的使得当前项目去注入日志记录器中的Bean ,
但是这样就暴露出一些问题
1 包名暴露了
2 使用起来不是特别的方便
经过大佬的指定,把注入Bean的功能放到日志记录器中,并且使用@EnableLogger注解实现此功能,使用的时候也能见名知意
作用
就是为了解决本项目的Bean不能在本项目注入,而需要在引入项目进行显式注入的问题(本项目的Bean由本项目注入)
自定义
第一步 定义一个配置文件,将本项目中所有Bean都返回并且使其配置文件和Bean定义能够被扫描
@Configuration public class LoggerConfig { // 一定要注入所有的Bean @Bean public LoggingAspects getLoggingAspects() { return new LoggingAspects(); } @Bean public LogMapper getLogMapper() { return new DefaultLogMapperImpl(); } @Bean public LoggingUtils getLoggingUtils() { return new LoggingUtils(); } @Bean public SpringUtils getSpringUtils() { return new SpringUtils(); } }
2 自定义一个注解(@EnableXXX),用于在别的项目使用时开启特定功能(本质就是注入特定的功能所需要的Bean)
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(LoggerEnableAutoConfig.class) //关注@Import() 注解及其导入的配置类 public @interface EnableLogger { }
到现在为止,知道@EnableLogger注解用于注入项目的Bean , 用在别的项目的主程序上,但是这个注解用在了那个主程序上,别的项目的主程序和本项目的配置文件是怎么勾连上的呢?这时候就是
@Import(LoggerEnableAutoConfig.class)
发挥作用的时候了
看名字就知道@Import注解导入一个自动配置类(LoggerEnableAutoConfig)
第三步 自定义自动配置类
@Slf4j @Configuration public class LoggerEnableAutoConfig implements ImportSelector { Logger logger = LoggerFactory.getLogger(LoggerEnableAutoConfig.class); @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { //判断主程序上是否存在指定注解 Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(EnableLogger.class.getName()); if(attributes == null){ log.info("@EnableLogger is not used on the main program"); return new String[0]; } return new String[]{LoggerConfig.class.getName()}; } }
编写一个实现了ImportSelector接口类
ImportSelector接口,查看其具体实现源码(根据AnnotationMetadata元数据注册bean类,即返回的Bean 会自动的被注入,被Spring所管理)
public interface ImportSelector { /** * Select and return the names of which class(es) should be imported based on * the {@link AnnotationMetadata} of the importing @{@link Configuration} class. * @return the class names, or an empty array if none */ String[] selectImports(AnnotationMetadata importingClassMetadata); }
这个接口返回的类的全类名对应的Bean都会被注入到IOC容器中
其实现自动配置的方式的底层就是通过@Import注解引入相关配置类,然后再在配置类将所需的bean注册到spring容器中和实现组件相关处理逻辑
-
spring boot 自定义@EnableXXX注解
2019-02-24 15:27:10spring boot 自带了很多@EnableXXX这样的注解,通过这些注解我们可以很方便地启用某些功能,比如@EnableAutoConfiguration用来开启自动装配的功能。内部实现主要是通过@Import注解将指定的类实例注入之Spring IOC ... -
Spring Boot @Enable*注解源码解析及自定义@Enable*
2019-02-14 18:13:33Spring Boot @Enable注解源码解析及自定义@Enable Spring Boot 一个重要的特点就是自动配置,约定大于配置,几乎所有组件使用其本身约定好的默认配置就可以使用,大大减轻配置的麻烦。其实现自动配置一个方式就是... -
Spring系列之手写自定义的@Enable*注解
2021-01-15 11:05:32我们经常会遇到@Enable开始的好多注解,比如@EnableWebMvc、@EnableEurekaServer、@EnableAsync、@EnableScheduling等,今天我们就来分析下这些注解到底是如何工作的,并写手自定的@Enable注解。 @Enable*实现的原理... -
Springboot的 @Enable*的原理以及如何 以及如何自定义@Enable*注解
2019-08-16 18:13:56因为spring boot会扫描启动类同包及子包中的bean, 而范围以外的bean 就需要用 上面三种方式注入到spring容器中。 比如:注解 和注解处理类,项目中如果使用jar包中的...spring Boot的 @Enable* 注解就是把引入注解处... -
16-SpringBoot自动配置-Enable注解原理
2022-03-08 01:00:0616-SpringBoot自动配置-Enable注解原理Enable注解原理@Enable* 注解SpringBoot提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。... -
Spring Boot 自定义@Enable* 注解
2020-03-27 23:42:17Spring Boot 自定义@Enable* 注解@Enable*的实例@EnableAsync通过实现ImportSelector接口来实现bean的加载通过实现ImportBeanDefinitionRegistrar接口来实现bean的加载自定义Enable注解来实现对类加载的监听 ... -
自定义Springboot @EnableXXX注解
2019-07-06 17:24:27上一篇大概讲了springboot 的@EnableAutoConfiguration的实现,这篇我们自定义一个@EnableMyCache注解实现。 1.利用@Import注解加载不在包扫描范围的类,并将其注册到容器。 2.我们知道将Bean注册到IOC容器有很多... -
springBoot @Enable* 注解的使用
2019-08-22 19:18:52这篇文章主要介绍了springBoot @Enable* 注解的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 1、为什么使用@SpringBootApplication注解,即可做到自动配置? 答:@... -
spring boot自定义日志注解
2021-05-26 15:07:451. maven配置 首先需要在maven的pom文件中配置依赖。... 使用自定义注解打印 自定义注解定义完成,可以在我们的方法上面来使用这个注解了,使用如下图 调用该方法时,就可以看到该注解所打印的日志了 -
spring boot starter--使用自定义@EnableXXX注解实现
2020-03-19 11:34:27spring boot启动的时候会自动扫描启动类上@Enable开头的注解,然后我们可以给@EnableXXX加上注解@Import,导入实现了ImportSelector或ImportBeanDefinitionRegistrar的类 新建spring-boot-stater工程:myTest2-... -
SpringBoot手动装配,自定义Enable模块
2020-08-12 19:35:28今天这篇文章主要是介绍下如何是实现手动配置,自定义Enable模块, -
Spring-Boot之@Enable*注解的工作原理
2018-10-16 22:28:33@enable*是springboot中用来启用某一个功能特性的一类注解。其中包括我们常用的@SpringBootApplication注解中用于开启自动注入的annotation@EnableAutoConfiguration,开启异步方法的annotation@EnableAsync,开启将... -
自定义注解扫描
2020-08-16 13:55:24扫描自定义注解有多种方式,这里通过实现ImportBeanDefinitionRegistrar类来进行自定义注解的扫描,并将其注入IOC容器中。ImportBeanDefinitionRegistrar类本身只能通过@Import方式进行注入,所以先来实现一个注解... -
【spring】自定义缓存注解
2022-04-26 13:49:43为什么要自定义缓存注解? Spring Cache本身提供@Cacheable、@CacheEvict、@CachePut等缓存注解,为什么还要自定义缓存注解呢? @Cacheabe不能设置缓存时间,导致生成的缓存始终在redis中,当然这一点可以通过修改... -
Spring-boot|如何自定义@Enable模块装配
2018-12-16 23:13:26在学习SpringBoot的时候,我们会使用到@Enable***注解的地方,使用上也都是加在@Configuration 类注解的类上面,比如: (1)@EnableAutoConfiguration 开启自动扫描装配Bean (2)@EnableScheduling 开启计划任务的... -
自定义springboot starter和自定义条件注解
2020-05-30 17:53:53设置myboot.enable=true或者缺省,然后设置myboot.status=OK和myboot.msg=hello myboot stater,再次启动 >>> spring boot 启动完成 自定义条件注解@MyConditionAnnotation @MyConditionAnnotation @Target({ ... -
springboot进阶(3):Enable注解
2022-03-31 17:44:49文章目录前言第一节、问题:引入一个jar能直接获取它的Bean吗pojo工程enable工程(引入pojo)第二节、如何获取到user这个Bean第一种、配置@ComponentScan第二种、配置@Import注解第三种、 配置@Enable注解 前言 @Enable... -
springBoot @Enable* 注解
2018-06-05 14:50:231、为什么使用@SpringBootApplication注解,即可做到自动配置? 答:@SpringBootApplication,内部起作用的注解其实有3个。@EnableAutoConfiguration,@ComponentScan,@Configuration。这篇文章主要是讲解@EnableXX... -
自定义注解使用@Import执行操作
2021-12-07 16:07:53注解,@Import -
自定义鉴权注解与AOP
2022-03-16 20:13:03} 自定义注解: /** * 鉴权注解 * */ @Target(ElementType.METHOD) // 注解范围,注解使用在方法上 @Retention(RetentionPolicy.RUNTIME) // 生效时间 @Documented public @interface Authenticate { /** * 服务code... -
如何自定义一个注解?
2020-06-03 17:20:09在Java中,类使用class定义,接口使用interface定义,注解和接口的定义差不多,增加了一个@符号,即@interface,代码如下: public @interface EnableAuth { } 注解中可以定义成员变量,用于信息的描述,跟接口中... -
使用Aop实现自定义注解 - 实战篇(统一日志打印)
2021-06-14 16:18:24使用Aop实现自定义注解- 原理篇 使用Aop实现自定义注解 - 实战篇(统一日志打印) 统一日志打印 约定大于配置,系统提供对外的接口要有以下要求,这样的好处是我们可以对接口统一做定制化日志管理。比如只对更新接口... -
springboot自定义注解没有生效_自定义注解:springboot+vue限制接口调用
2020-11-21 09:54:30四、使用自定义注解 @EnableAuth @PostMapping(value = "/login") public ResultData login(String username, String password) { logger.info("------用户登录 login:{} start", "username:" + username + ... -
springboot自定义注解@和拦截器
2020-08-25 16:38:50考虑到并不是所有的请求都需要进行参数校验,这还可以有另一种实现方法: 自定义注解@ 1、自定义注解接口 import java.lang.annotation.*; //注解信息会被添加到Java文档中 @Documented //注解的生命周期,表示注解... -
Spring中@Enable功能开关注解的实现
2020-12-18 11:19:10经常会用到Spring项目中@EnableXXX这种注解,都是用来启用某种功能,这种注解类似于一种开关,加了这个注解,就能使用某些功能。例如@EnableAsync、@EnableScheduling 等注解。 Srping实现Enable模块驱动的方法大致... -
SpringBoot之Enable注解(自动配置)
2020-03-22 17:45:54 声明:SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态开启某些功能的,而其底层原理是使用@Import注解导入一些配置类,实现Bean的动态加载,第三方jar包中的也可以通过此注解进行配置 @Enable底层...