• 004-搭建框架-实现AOP机制【一】代理技术


    前景提要

      监控方法性能、执行时间、记录日志等

      AOP( Aspect Oriented Programming)面向方面编程。

      在AOP中,需要定义一个Aspect(切面)类来编写需要横切业务的逻辑代码,例如上面提到的性能监控代码。此外,还需要通过一个条件来匹配想要拦截的类,这个条件在AOP中称为PointCut(切点)。

    技术点

      代理技术

      使用Spring提供的AOP技术

      使用动态代理技术实现AOP框架

      使用ThreadLocal技术

      数据库事物管理机制

      使用AOP框架实现事物控制

    一、代理技术

      代理,Proxy。aop是代理的一种实现。Http代理等

    1.1、静态代理

      示例  

    public interface Hello {
        void say(String name);
    }

      实现

    public class HelloImpl implements Hello {
        @Override
        public void say(String name) {
            System.out.println("Hello! " + name);
        }
    }

      如,在说前后增加操作。

      初级代理实现:

    public class HelloProxy implements Hello {
        private Hello hello;
        public HelloProxy() {
            this.hello = new HelloImpl();
        }
        @Override
        public void say(String name) {
            before();
            hello.say(name);
            after();
        }
        private void before(){
            System.out.println("Before");
        }
        private void after(){
            System.out.println("After");
        }
    }

      测试主类:  

            Hello helloProxy = new HelloProxy();
            helloProxy.say("muzixu");

      输出:

    Before
    Hello! muzixu
    After

    其实,以上helloProxy 就是代理。

    1.2、JDK动态代理

    第一次 编写

      使用JDK方案的一个动态代理

    public class DynamicProxy implements InvocationHandler {
        private Object target;
    
        public DynamicProxy(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object result = method.invoke(target,args);
            after();
            return result;
        }
    
    
        private void before(){
            System.out.println("Before");
        }
        private void after(){
            System.out.println("After");
        }
    }

      在DynamicProxy 类中定义了一个Object的target变量,他就是被代理的目标对象。通过构造函数来初始化【即注入】。

      该类实现了InvocationHandler 接口,需要实现的方法即invoke。在该方法中,直接通过反射去invoke method,在调用前后分别before,after,最后返回结果。

      调用

            Hello hello=new HelloImpl();
            DynamicProxy dynamicProxy=new DynamicProxy(hello);
            Hello helloProxy = (Hello)Proxy.newProxyInstance(hello.getClass().getClassLoader(),
                    hello.getClass().getInterfaces(),
                    dynamicProxy);
            helloProxy.say("muzixu");

      用通用的DynamicProxy 类去包装HelloImpl实例,然后在调用JDK提供的Proxy类的工厂方法newProxyInstance去动态的创建一个Hello接口的代理类,最后调度用这个代理类的方法。

      结果同上一致。

    第二次 优化  

    public class DynamicProxy2 implements InvocationHandler {
        private Object target;
    
        public DynamicProxy2(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object result = method.invoke(target, args);
            after();
            return result;
        }
    
        public <T> T getProxy() {
            return (T) Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    this);
        }
    
        private void before() {
            System.out.println("Before");
        }
    
        private void after() {
            System.out.println("After");
        }
    }

      使用

            DynamicProxy2 dynamicProxy=new DynamicProxy2(new HelloImpl());
            Hello helloProxy = dynamicProxy.getProxy();
            helloProxy.say("muzixu");

    其实就是将实例化过程抽象。

    对比一下

    名称 优点 缺点
    静态代理   接口变了,实现类需要变,代理类也要变
    JDK动态代理 接口变了,代理类不变 无法代理没有实现任何一个接口的类
    CGlib动态代理

    运行期间动态生成字节码的工具

    也就是动态生成代理类

     

    1.3、CGlib动态代理

      spring,hibernate等使用

      pom:

        <dependencies>
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>3.1</version>
            </dependency>
        </dependencies>

    第一次实例

    public class CGLibProxy implements MethodInterceptor {
        public <T> T getProxy(Class<T> cls) {
            return (T) Enhancer.create(cls,this);
        }
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object result = methodProxy.invokeSuper(o,objects);
            after();
            return result;
        }
        private void before() {
            System.out.println("Before");
        }
    
        private void after() {
            System.out.println("After");
        }
    }

      使用

            CGLibProxy proxy = new CGLibProxy();
            Hello hello = proxy.getProxy(HelloImpl.class);
            hello.say("muzixu");

    第二次 单例模式构建

    public class CGLibSingleProxy implements MethodInterceptor {
        private static CGLibSingleProxy instance = new CGLibSingleProxy();
        private CGLibSingleProxy(){
        }
        public static CGLibSingleProxy getInstance(){
            return instance;
        }
        public <T> T getProxy(Class<T> cls) {
            return (T) Enhancer.create(cls,this);
        }
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            Object result = methodProxy.invokeSuper(o,objects);
            after();
            return result;
        }
        private void before() {
            System.out.println("Before");
        }
    
        private void after() {
            System.out.println("After");
        }
    }

      调用

            Hello hello = CGLibSingleProxy.getInstance().getProxy(HelloImpl.class);
            hello.say("muzixu");
  • 相关阅读:
    第15周作业
    迟到的第14周作业
    第13周作业集
    第11次作业--字符串处理
    找回感觉的练习
    第9次作业--接口及接口回调
    20194684 + 自动生成四则运算题第一版报告
    css的calc在less文件中计算有误问题
    react 细节整理
    js async属性
  • 原文地址:https://www.cnblogs.com/bjlhx/p/7689581.html
Copyright © 2020-2023  润新知