Java装饰者模式、动态代理机制,Spring AOP,CGLib字节码增强

Java的动态代理机制:

        Java的动态代理机制又称jdk动态代理依赖接口实现,只能代理实现了接口的类。动态代理是对“装饰者”模式的简化。
        动态代理类的字节码在程序运行时由Java反射机制动态生成(因为Java反射机制可以生成任意类型的动态代理类),无需程序员手工编写它的源码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性。java.lang.reflect包中的Proxy类和InvovationHandler接口提供了生成动态代理类的能力。
参考:
http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
https://blog.csdn.net/su20145104009/article/details/53526557
https://www.cnblogs.com/xiaoluo501395377/p/3383130.html

编写过程:

1、目标类(被代理类):接口 + 实现类
2、切面类:用于存放通知(或者抽取出的可以共同使用的部分)
3、Handler:代理实例相关联的调用处理程序
4、工厂类:编写工厂用于生成代理
5、测试

UserService接口

public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

UserService实现类(需要被代理的对象)

public class UserServiceImpl implements UserService {
    public void addUser() {
        System.out.println("UserServiceImpDAO add User!");
    }
    public void updateUser() {
        System.out.println("UserServiceImpDAO update User!");
    }
    public void deleteUser() {
        System.out.println("UserServiceImpDAO delete User!");
    }
}

切面类

public class Aspect {
    public void before() {
        System.out.println("before~");
    }
    public void after() {
        System.out.println("after~");
    }
}

Handler

InvocationHandler的官方解释

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

        InvocationHandler是代理实例的调用处理器Handler(Handler即为Controller控制器)必须实现的接口,每一个代理实例(proxy instance)都有一个相关联的调用处理器Handler。当代理实例的方法被调用时,该方法调用会被编码,然后分派给代理实例相关联的Handler的invoke方法进行处理。这就是代理的核心。

//调用处理器(Handler)把被代理类和切面类结合起来
public class MyDynamicProxyHandler implements InvocationHandler {
    Object proxiedRealObject;
    public MyDynamicProxyHandler(Object proxiedRealObject) {
        this.proxiedRealObject = proxiedRealObject;
    }
    @Override
    public Object invoke(Object proxiedObject, Method method, Object[] parms) throws Throwable {
        Object obj = null;
        //切面类
        final Aspect aspect = new Aspect();
        aspect.before();
        //执行目标类的方法。Method对象的invoke方法:用指定的参数(parms)调用指定对象(proxiedRealObject)中的method相关的方法。
        obj = method.invoke(proxiedRealObject, parms);
        aspect.after();
        //返回被代理类的方法执行后的结果
        return obj;
    }
}

解释invoke方法
        代理对象调用被代理类的方法时,都会调用一次该invoke方法,对参数进行解释:

  1. proxiedObject:被代理的对象
  2. method:代理对象执行当前执行(的被代理对象)的方法
  3. parms:当前执行方法的参数列表

PS:我们可以根据method.getName()获取当前调用方法的信息,针对特定的method实现特定的功能
比如:我们只给addUser添加before和after方法,对上述的invoke方法做如下的修改。

public Object invoke(Object proxiedObject, Method method, Object[] parms) throws Throwable {
        Object obj = null;
        if("addUser".equals(method.getName())) {
            final Aspect aspect = new Aspect();
            aspect.before();
            obj = method.invoke(proxiedRealObject, parms);
            aspect.after();
        } else {
            obj = method.invoke(proxiedRealObject, parms);
        }
        return obj;
    }

工厂类

用于生成代理

public class MyProxyFactory {
    public static Object createUserService() {
        //目标类实例(被代理类实例)
        final UserService userServiceImpl = new UserServiceImpl();
        //调用处理器
        final MyDynamicProxyHandler handler = new MyDynamicProxyHandler(userServiceImpl);
        //代理实例
        Object proxy = Proxy.newProxyInstance(MyProxyFactory.class.getClassLoader(), userServiceImpl.getClass().getInterfaces(), handler);
        return proxy;
    }
}

解释Proxy.newProxyInstance

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

        Proxy类提供了一系列静态方法,这些方法都是首先查找或者创建指定的代理类(实现interfaces中所有接口的动态代理类),然后使用指定的InvocationHandler调用构造函数生成该动态代理类的实例。最后返回该实例,这个实例分派方法调用到指定的handler的invoke上。

  • 函数原型 public static Object(ClassLoader loader, Class<?>[] Interfaces, InvocationHandler h) throws IllegalArgumentException;
  • 参数列表

    1. loader:类加载器对象。动态代理类是运行时创建的(如上所述),任何类都需要类加载器加载到内存中,所以使用它来加载该动态生成的代理类。一般使用当前类.class.getClassLoader()(如:MyProxyFactory.class.getClassLoader())或者使用被代理类.getClass.getClassLoader()(如:userServiceImpl.getClass.getClassLoader())。
      (问:可以随便儿使用类加载器嘛?还是不同类的类加载器是不一样的?只要是类加载器就能加载?)
    2. interfaces:代理类要实现的所有接口:被代理类.getClass().getInterfaces()。
    3. handler:当前动态代理对象在调用方法时会关联到的InvocationHandler。该Handler必须实现InvocationHandler接口(该Handler一般以匿名内部类的形式提供),必须重写其中的invoke方法。每次通过代理对象调用被代理对象的方法时(如:下面的userService.addUser()等),都会调用一次该invoke方法。

测试类
PS:如果被代理类实现了多个接口,那么生成的代理对象可以被转换为多种接口类型,就实现了多态。

public class TestProxy {
    public static void main(String[] args) {
        //生成代理对象。由于代理类实现了被代理类的所有接口,所以生成的代理类可以被强制转换为userService。
        UserService userService = (UserService)MyProxyFactory.createUserService();
        //调用通过调用代理对象的方法来被代理对象的方法。
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }
}

运行结果
这里写图片描述
提问:
代理对象调用方法时,如何分派给Handler的invoke方法执行的???????

CGLib动态代理

        采用字节码增强框架CGLib,底层使用反射机制,在运行时动态创建目标的子类(代理类),从而对目标类进行增强。
        由于JDK的动态代理机制只能代理实现了接口的类,而没有实现接口的类不能不能被JDK动态代理机制代理,为了弥补JDK动态代理机制的这个缺陷,CGLib针对类来实现代理,它的原理是对指定的目标类(可以实现或者不实现接口)生成一个子类,即:目标类为生成的代理类的父类,并且覆盖父类中的方法来实现目标类增强(采用的是继承)。cglib.proxy.Enhancer类和callback接口提供了实现CGLib动态代理的支持。
参考:
http://www.cnblogs.com/xrq730/p/6661692.html

MethodIntercepter接口

        Callback是一个空的接口,没有任何方法,他只是表示这是一个回调。其中最常使用的是callback接口的子接口MethodIntercepter

编写过程

1、目标类:被代理类(无需实现接口)
2、切面类:用于存放通知(或者抽取出的可以共同使用的部分)
3、Callback:给代理类设置回调,对代理类方法的调用都会调用Callback
4、工厂类:编写工厂用于生成代理
5、测试

目标类

package org.springframework.samples.mvc.CGLib;

public class UserServiceImpl{
    public void addUser() {
        System.out.println("CGLib UserServiceImpDAO add User!");
    }
    public void updateUser() {
        System.out.println("CGLib UserServiceImpDAO update User!");
    }
    public void deleteUser() {
        System.out.println("CGLib UserServiceImpDAO delete User!");
    }
}

切面类

package org.springframework.samples.mvc.CGLib;

public class Aspect {
    public void before() {
        System.out.println("before~");
    }
    public void after() {
        System.out.println("after~");
    }
}

Callback

CGLib和JDK动态代理的区别之处1(callback与handler的区别):
        设置的回调函数MethodIntercepter接口等效于jdk invocationHandler接口,MethodIntercepter.intercept()方法拦截器等效于invocationHandler.invoke()。intercept()的参数1、参数2、参数3和invoke()的三个参数一样。其中的参数4: methodProxy是代理方法,可以使用它来执行父类方法。

package org.springframework.samples.mvc.CGLib;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class MyDynamicProxyCallback implements MethodInterceptor {
    Object proxiedRealObject;
    public MyDynamicProxyCallback(Object proxiedRealObject) {
        this.proxiedRealObject = proxiedRealObject;
    }
    //回调方法
    @Override
    public Object intercept(Object proxiedObj, Method method, Object[] args, MethodProxy proxy) throws Throwable{
        Aspect aspect = new Aspect();
        aspect.before();
        Object obj = method.invoke(proxiedRealObject, args);
        //写下invokeSuper()
        aspect.after();
        return obj;
    }
}

工厂类

CGLib和JDK动态代理的区别之处2(Enhance和Proxy的区别)

package org.springframework.samples.mvc.CGLib;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;

public class MyProxyFactory {
    public static Object createUserService() {
        UserServiceImpl userServiceimp = new UserServiceImpl();
        Callback callback = new MyDynamicProxyCallback(userServiceimp);
        //创建加强器,用来生成动态代理类
        Enhancer enhancer = new Enhancer();
        //为加强器指定要代理的目标类
        enhancer.setSuperclass(userServiceimp.getClass());
        //设置回调:对于代理类上的所有方法调用,都会去调用Callback,Callback必须实现intercept方法进行拦截。
        enhancer.setCallback(callback);
        //创建动态代理类对象并返回
        Object proxy = enhancer.create();
        return proxy;
    }
}

猜你喜欢

转载自blog.csdn.net/u011523796/article/details/80085866
今日推荐