前言
上一篇文章讲了@Import的源码,还有就是这个注解的一些功能用法。那这一篇就是实际情况的一些运用了。 其实自定义一个@EnableXXX注解还是挺简单的,大概就是自己定义一个@EnableXXX注解,然后在加上一个@Import注解导入配置,就差不多了。 那下面来具体实现一个自定义的@EnableXXX注解。主要就是做一个异步任务,就是和@EnableAsync是一样的,不过与其比起来就差很多了。
正文
注意点,还是和上篇一样的,在启动类的上级目录下创建该注解,比如启动类在a.b.c.d下,那该注解在a.b.c下,主要就是要与启动类分开。
- 创建基础注解,在方法上标记了该注解,代表该方法会异步执行
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAsync {
}
- 创建AOP的Advice(实现MethodInterceptor接口)
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;
}
}
- 创建配置类
@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的时候尽量使用注解,这样粒度就比较细,修改也比较方便。
- 创建自定义注解@EnableTestAsync
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfig.class)
public @interface EnableTestAsync {
}
这里为了简单快捷,我用的是配置类,一般都是是用ImportSelector或ImportBeanDefinitionRegistrar的实现类, 因为@EnableXXX注解里面也会有属性值,而这两个接口的实现类是能获取到注解的信息。
- 使用注解 5.1 先在启动类上面添加@EnableTestAsync注解,使其生效。 5.2 新建接口和实现类
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 调用
@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();
}
}
运行结果:
TestAsyncServiceImpl.testAsync() run 。。。
AsyncInterceptor run before ... Thread-2
TestAsyncServiceImpl.testAsyncA() run 。。。
AsyncInterceptor run after ...Thread-2
这样一个简单的自定义@EnableXXX注解就完成了,当然,问题还是挺多的。