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");

 

posted @ 2017-10-18 22:46  bjlhx15  阅读(230)  评论(0编辑  收藏  举报
Copyright ©2011~2020 JD-李宏旭