自定义EnableXXX注解

图片

前言

上一篇文章讲了@Import的源码,还有就是这个注解的一些功能用法。那这一篇就是实际情况的一些运用了。 其实自定义一个@EnableXXX注解还是挺简单的,大概就是自己定义一个@EnableXXX注解,然后在加上一个@Import注解导入配置,就差不多了。 那下面来具体实现一个自定义的@EnableXXX注解。主要就是做一个异步任务,就是和@EnableAsync是一样的,不过与其比起来就差很多了。

正文

注意点,还是和上篇一样的,在启动类的上级目录下创建该注解,比如启动类在a.b.c.d下,那该注解在a.b.c下,主要就是要与启动类分开。

  1. 创建基础注解,在方法上标记了该注解,代表该方法会异步执行
1
2
3
4
5
6
7

    @Target({ElementType.TYPE,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface TestAsync {
    }

  1. 创建AOP的Advice(实现MethodInterceptor接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

    public class AsyncInterceptor implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            new Thread(() -> {
                try {
                    System.out.println("AsyncInterceptor run before ... " + Thread.currentThread().getName());
                    methodInvocation.proceed();
                    System.out.println("AsyncInterceptor run after ..." + Thread.currentThread().getName());
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }).start();
            return null;
        }
    }

  1. 创建配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

    @Configuration
    public class AsyncConfig {
        @Bean
        public DefaultPointcutAdvisor defaultPointcutAdvisor1(){
            AsyncInterceptor asyncInterceptor=new AsyncInterceptor();
            // 1. 注解方式
            AnnotationMatchingPointcut pointcut=new AnnotationMatchingPointcut(null,TestAsync.class);
            // 2.
            // JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
            // pointcut.setPatterns("");
            DefaultPointcutAdvisor advisor=new DefaultPointcutAdvisor();
            advisor.setPointcut(pointcut);
            advisor.setAdvice(asyncInterceptor);
            return advisor;
        }
    }

这里需要注意的是第一种方式的Pointcut,第一个参数为null,不然就无法实现功能,需要注意AnnotationMatchingPointcut构造函数的不同的作用。 还有就是在定义Pointcut的时候尽量使用注解,这样粒度就比较细,修改也比较方便。

  1. 创建自定义注解@EnableTestAsync
1
2
3
4
5
6
7
8

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AsyncConfig.class)
    public @interface EnableTestAsync {
    }

这里为了简单快捷,我用的是配置类,一般都是是用ImportSelector或ImportBeanDefinitionRegistrar的实现类, 因为@EnableXXX注解里面也会有属性值,而这两个接口的实现类是能获取到注解的信息。

  1. 使用注解 5.1 先在启动类上面添加@EnableTestAsync注解,使其生效。 5.2 新建接口和实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    public interface TestAsyncService {
        void testAsync();
        void testAsyncA();
    }

    @Service
    public class TestAsyncServiceImpl implements TestAsyncService {
        @Override
        public void testAsync() {
            System.out.println("TestAsyncServiceImpl.testAsync() run 。。。 ");
        }
    
        @Override
        @TestAsync
        public void testAsyncA() {
            System.out.println("TestAsyncServiceImpl.testAsyncA() run 。。。 ");
        }
    }

5.3 调用

1
2
3
4
5
6
7
8
9
10
11
12

    @SpringBootApplication
    @EnableTestAsync
    public class SpringBootTwoApplication {
        public static void main(String[] args) {
            ConfigurableApplicationContext run = SpringApplication.run(SpringbootTwoApplication.class, args);
            TestAsyncService bean = run.getBean(TestAsyncService.class);
            bean.testAsync();
            bean.testAsyncA();
        }
    }

运行结果:

1
2
3
4
5
6

    TestAsyncServiceImpl.testAsync() run 。。。 
    AsyncInterceptor run before ... Thread-2
    TestAsyncServiceImpl.testAsyncA() run 。。。 
    AsyncInterceptor run after ...Thread-2

这样一个简单的自定义@EnableXXX注解就完成了,当然,问题还是挺多的。

坚持原创技术分享,您的支持将鼓励我继续创作!