SpringAOP总揽

1.AOP概念:ASPECT、JOIN POINT和ADVICE如何理解?

a.形象理解为:ASPECT是一个Class类,而Join points具体到某个要执行的点上,相当于是一个方法,Pointcnt是一个匹配Join points的条件,advice即为@before,@Around等.

b.ASPECT->N个Join points->N个advice ,即他们的对应关系为1对N对N。

2.JAVA AOP设计模式

  • 代理模式:动态代理和静态代理
    public static void main(String[] args) {
    // class $proxy0 extend proxy implements EchoService {
        //   $proxy0(InvocationHandler handler) {
        //      super(handler);
        //   }
        // }
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    
            Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {
                        ProxyEchoService proxyEchoService = new ProxyEchoService(new DefaultEchoService());
                        return proxyEchoService.echo((String) args[0]);
                    }
                    return null;
                }
            });
    
            EchoService echoService = (EchoService) proxy;
            echoService.echo("Hello,World");
        }

  • 判断模式:类、方法、注解、参数、异常...
  • 拦截模式:前置、后置、返回、异常

3.AOP判断模式,如何筛选Join Point

public static void main(String[] args) {
        String targetClassName = "com.huawei.spring.aop.overview.EchoService";
        //获取当前线程的加载器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        try {
            Class<?> targetClass = classLoader.loadClass(targetClassName);
        // 方法定义:String echo(String message);
        // Spring 反射工具类
            Method targetMethod = ReflectionUtils.findMethod(targetClass, "echo", String.class);
            System.out.println(targetMethod);

            ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    System.out.println("仅抛出异常为Null的方法为:" + method);
                }
            }, new ReflectionUtils.MethodFilter() {
                @Override
                public boolean matches(Method method) {
                    Class[] parameterTypes = method.getParameterTypes();
                    Class[] exceptionTypes = method.getExceptionTypes();
                    return parameterTypes.length == 1
                            && String.class.equals(parameterTypes[0])
                            && exceptionTypes.length == 1
                            && NullPointerException.class.equals(exceptionTypes[0]);
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

4.AOP拦截模式

主要通过接口实现热插拔,用户只需要关注接口里面的实现,而不需要关注业务逻辑

public static void main(String[] args) {
        // 前置模式 + 后置模式
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {
                    // 前置拦截器
                    BeforeInterceptor beforeInterceptor = new BeforeInterceptor() {
                        @Override
                        public Object before(Object proxy, Method method, Object[] args) {
                            return System.currentTimeMillis();
                        }
                    };
                    Long startTime = 0L;
                    Long endTime = 0L;
                    Object result = null;
                    try {
                        // 前置拦截
                        startTime = (Long) beforeInterceptor.before(proxy, method, args);
                        EchoService echoService = new DefaultEchoService();
                        result = echoService.echo((String) args[0]); // 目标对象执行
                        // 方法执行后置拦截器
                        AfterReturnInterceptor afterReturnInterceptor = new AfterReturnInterceptor() {
                            @Override
                            public Object after(Object proxy, Method method, Object[] args, Object returnResult) {
                                return System.currentTimeMillis();
                            }
                        };
                        // 执行 after
                        endTime = (Long) afterReturnInterceptor.after(proxy, method, args, result);
                    } catch (Exception e) {
                        // 异常拦截器(处理方法执行后)
                        ExceptionInterceptor interceptor = (proxy1, method1, args1, throwable) -> {
                        };
                    } finally {
                        // finally 后置拦截器
                        FinallyInterceptor interceptor = new TimeFinallyInterceptor(startTime, endTime);
                        Long costTime = (Long) interceptor.finalize(proxy, method, args, result);
                        System.out.println("echo 方法执行的实现:" + costTime + " ms.");
                    }

                }
                return null;
            }
        });

        EchoService echoService = (EchoService) proxy;
        echoService.echo("Hello,World");
    }

5.CGLIB动态代理

为什么java动态代理无法满足AOP需要?

  JDK只能代理接口的方法,接口实现类的其它方法不能代理。Cglib是通过继承被代理类创建的代理类,所以可以代理非接口的方法,甚至普通类没有实现接口,Cglib也是可以代理的。Cglib使用字节码提升来实现AOP,具体代码如下:

public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        // 指定 super class = DefaultEchoService.class
        Class<?> superClass = DefaultEchoService.class;
        enhancer.setSuperclass(superClass);
        // 指定拦截接口
        enhancer.setInterfaces(new Class[]{EchoService.class});
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object source, Method method, Object[] args,
                                    MethodProxy methodProxy) throws Throwable {
                long startTime = System.currentTimeMillis();
                // Source -> CGLIB 子类
                // 目标类  -> DefaultEchoService
                // 错误使用
//                Object result = method.invoke(source, args);
                // 正确的方法调用
                Object result = methodProxy.invokeSuper(source, args);
                long costTime = System.currentTimeMillis() - startTime;
                System.out.println("[CGLIB 字节码提升] echo 方法执行的实现:" + costTime + " ms.");
                return result;
            }
        });

        // 创建代理对象
        EchoService echoService = (EchoService) enhancer.create();
        // 输出执行结果
        System.out.println(echoService.echo("Hello,World"));
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值