切面功能就当下大多数公司项目都会用到,切面编程的有点这里就不多说了,《关于Spring aop的理解》一篇我个人关于SpringAop的一些理解和想法。
这篇文章主要是Spring Aop的实战。
网上关于Spring Aop配置式的博客太多,这里也不再做重复工作,重点是介绍一下注解方式的实现。
一. 通配符配置的方式
二. 自定义注解
我们现在自己一些特定的方法上添加切面功能怎么办?如果使用通配符就需要按照通配符定义的规则(如包的路径,类方法的取名等),我们想更灵活些怎么办?这时候用注解标记方法就是一个比较好的选择,被标记的方法才执行我们的增强逻辑。
1). 声明我们的注解:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface MyLogger {
String name() default "MyLogger";
boolean test() default false;
}
2). 注解功能的实现类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyLoggerAspect {
@Around(value = "@annotation(logger)", argNames = "joinPoint,logger")
public Object sayHello(ProceedingJoinPoint joinPoint, MyLogger logger) {
Object obj = null;
try {
System.out.println(logger.name() + " do somethings start....");
obj = joinPoint.proceed();
System.out.println(logger.name() + " do somethings end....");
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
System.out.println(logger.name() + " finally....");
}
return obj;
}
}
3). 测试类
import org.springframework.stereotype.Component;
@Component
public class TestService {
private String name = "testService";
public TestService() {
System.out.println(this.name + "create----------");
}
// 使用我们定义的注解
@MyLogger(name = "com.platform.mst.helper.replacecomponent.TestService.testAop")
public String testAop(){
return "testAop----------";
}
}
调用测试:
执行结果:
-----------------------------------------------------分隔符---------------------------------------------
以上就是我们的切面标记注解的实现与使用,但是我们想加在类上,让类的所有public
方法被代理怎么办?
有人说,那我们在注解上加上@Target(ElementType.TYPE)
不就行了?是可以给注解加上,但是这么做根本没效果,发现标记的类没有被代理。但是我就想实现这个功能,怎么办?
这里我们来实现一个统一异常处理的注解,功能就是catch标记类所有公共方法的异常(写到这里想偷懒了怎么办?。。。。。。直接贴代码吧)
import java.lang.annotation.*;
/**
* @Description 统一异常处理注解
* @Author lix <sclx1220@163.com>
* @Date 2020/7/17
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface ExceptionHandler {
Class value() default RuntimeException.class;
}
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* @Description 我们的代理增强类,需要增强的方法写在这里面
* @Author lix <sclx1220@163.com>
* @Date 2020/7/17
*/
public class ExceptionHandlerObject implements MethodInterceptor {
private Object target;
public ExceptionHandlerObject(Object target) {
System.out.println("生成代理对象:" + target.getClass());
this.target = target;
}
public Object getInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 设置回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if(method.getModifiers() != Modifier.PUBLIC){
return method.invoke(target, args);
}
Object result = null;
try {
System.out.println("ExceptionHandlerObject开始。。。");
result = methodProxy.invokeSuper(object, args);
System.out.println("ExceptionHandlerObject结束。。。");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("ExceptionHandlerObject统一异常处理。。。");
} finally {
System.out.println("ExceptionHandlerObject---finally。。。");
}
return result;
}
}
/**
* @Description 将我们的代理类交由spring管理。
* 注:MyService接口相当于@Component功能,这里是我自定的,
* 这块可以查看我的另一篇博文:{@Link https://blog.csdn.net/qq1170993239/article/details/106999915}
* @Author lix <sclx1220@163.com>
* @Date 2020/7/17
*/
public class MyControllerAspect implements MyService, BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean.getClass().getAnnotation(ExceptionHandler.class) == null){
return bean;
}
ExceptionHandlerObject handlerObject = new ExceptionHandlerObject(bean);
return handlerObject.getInstance();
}
}
我们的测试类:
我们调用contrller接口查看控制台的打印信息:
2020-07-17 10:14:53.039 INFO 11248 --- [nio-9090-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 19 ms
ExceptionHandlerObject开始。。。
java.lang.ArithmeticException: / by zero
at com.platform.mst.helper.controller.TestLockController.testExceptionHandler3(TestLockController.java:40)
.....省略中间堆栈打印.....
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
ExceptionHandlerObject统一异常处理。。。
ExceptionHandlerObject---finally。。。
2020-07-17 10:14:56.755 INFO 11248 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
到此本篇文章结束!!!