代理

什么是代理

代理是一个比较通用的词,作为一个设计模式,它的基本概念和日常生活中的概念是类似的,既就是:为其他对象提供一种代理以控制对这个对象的访问。
代理背后一般至少会有一个实际对象,代理的外部功能和实际对象一般一样,用户与代理打交道,不直接接触实际对象。

代理存在的价值

  1. 节省成本比较高的实际对象的创建开销,按需延迟加载,创建代理时并不真正的创建实际对象,而只是保存实际对象的地址,在需要时再加载或者创建。
  2. 执行权限检查、代理检查权限后、再调用实际对象。
  3. 屏蔽网络差异和复杂性,代理在本地,而实际对象在其他服务器上,调用本地代理时,不呢地代理请求其他服务器。

    静态代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class StaticProxyDemo{
    //定义接口Testservice
    static interface TestService{
    public void sayByebye();
    }
    //定义RealService实现TestService接口
    static Class RealService implements TestService{
    @Override
    public void sayByeBye(){
    System.out.println{"Bye"};
    }
    }
    //定义TracePorxy实现TestService,然后RealService作为它的成员变量,并重写其构造方法,再构造方法中对RealService进行初始化
    static Class TraceProxy implements TestService{
    private TestService realService;
    public TraceProxy(TestService realService){
    this.realService=realService;
    }
    @Override
    public void sayByeBye(){
    System.out.println{"start say Bye"};
    this.realService.sayByeBye();
    System.out.println{"end say Bye"};
    }
    }
    //执行过程如下
    public static void main(String [] args){
    //new一个实际的对象
    TestService realService=new RealService();
    //调用代理对象,并对它的成员变量进行初始化
    TestService porxyService=new TraceProxy(realService);
    //代理对象将实际上调用了实际对象的sayByeBye方法
    porxyService().sayByeBye();
    }
    }

    JDK代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class JDKDynamicProxyDemo{
    //定义接口Testservice
    static interface TestService{
    public void sayByebye();
    }
    //定义RealService实现TestService接口
    static Class RealService implements TestService{
    @Override
    public void sayByeBye(){
    System.out.println{"Bye"};
    }
    }

    static class TestInvocationHandler implements InvocationHandler{
    private Object realObject;
    public TraceProxy(Object realObject){
    this.Object=realObject;
    }
    @Override
    public Object invoke(Object proxy,Method method,Object[] args)
    throws Throwable{
    System.out.println{method.getName()};
    Object result=method.invoke(realObject,args);
    System.out.println{method.getName()};
    return result;
    }
    }

    public static void main(String [] args){
    TestService realService=new RealService();
    TestService porxyService=(TestService)Proxy.newProxyInstance(
    TestService.class.getClassLoader(),new Class<?>[]{TestService.class},
    new TestInvocationHandler(realService));
    porxyService().sayByeBye();
    }
    }

    jdk虽然也有动态代理,但是有一定的局限性,它只能给接口创建代理,返回的代理对象也只能转换到某个接口类型,如果一个类没有接口,或者希望可以代理非接口中定义的方法就没有办法。

    cglib代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class CglibDynamicPorxy{
    public class RealService{
    public void sayBye{
    System.out.println("hello");
    }
    }


    static class simpleInterceport impelments MethodInterceptor{
    @Override
    public Objec intercept(Object object,Method method,Object[] args,
    MethodProxy proxy) throws Throwable{
    System.out.println(method.getName());
    Object result=proxy.invokeSuper(object,args);
    //1.通过Proxy.getProxyCalss创建代理类的定义,类定义会被缓存
    //Class<T> proxyCls=Proxy.getProxyClass(TestService.class.getClassLoader(),
    //new Class<?>[]{TestService.class});
    //2.获取代理类的构造方法,构造方法有一个InvocationHandler类型的参数。
    //Constructor<?> ctor=proxyCls.getConstructor(new Class<?>[]{InvocationHandler.class});
    //3.创建InvocationHandler对象,创建代理类对象。
    //InvocationHandler handler=new SimpleInvocationHandler(realService);
    //TestService proxyService=ctor.newInstance(handler);
    System.out.println(method.getName());
    return result;
    }
    private static <T> T getProxy(Class<T> cls){
    Enhancer enhancer=new Enhancer();
    enhancer.setSuperclass(cls);
    enhancer.setCallback(new simpleInterceport());
    return (T) enhancer.create();
    }
    }
    public static void main(String [] args)throws Exception{
    RealService porxyService=simpleInterceport.getProxy(RealService.class);
    porxyService.sayBye();
    }
    }

    RealService表示被代理的类,没有接口,getProxy()为一个类生成代理对象,这个dialing可以安全的被转换为代理类的类型,过程中使用了cglib的Enhancer类。Enhancer类的setSuperclass设置被代理的类,setCallback设置被代理类的public非final方法被调用时的处理类。Enhancer支持多种类型。这里使用的类实现了MethodInterceptor接口,跟JDK中的InvocationHandler有点类似,方法名变成了intercept,并且多了一个proxyMehtod参数。

    JDK代理跟cglib代理的区别

  4. jdk代理面向的是接口,它给这些接口动态创建了一个实现类,接口的具体实现逻辑是通过自定义的InvocationHandler实现的,这个实现是自定义的。也就是说,其背后都不一定有真正代理的对象,可能有多个对象,根据情况动态选择。
  5. cglib代理面向的是一个具体的对象,它动态的创建了个新类,继承了该类,重写了其方法。
  6. jdk代理的是对象,首先需要一个实际对象,自定义的InvocationHandler引用该对象,客户端访问的是代理对象,再由代理对象调用实际对象的方法。
  7. cglib代理的类,创建的对象只有一个。

    动态代理的应用AOP

  8. 定义一个新的注解@Aspect
    1
    2
    3
    4
    5
    @Retention(RUNTIME)
    @Target(TYPE)
    public @interface Aspect{
    Class<?>[] value();
    }
  9. 定义日志切面类ServiceLogAspect(这样写的目的就是在类ServiceA和ServiceB所有的方法执行前后加一些日志)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spect(ServiceA.class,ServiceB.class)
    public class ServiceLogAspect{
    public static void before(Object object,Method method,Object [] args){
    System.out.println("entering"+
    method.getDeclaringClass().getSimpleName()+"::"+method.getName());
    }
    public static void after(Object object,Method method,Object[] args,
    Object result){
    System.out.println("ending"+
    method.getDeclaringClass().getSimpleName()+"::"+method.getName()+"result="+result);
    }
    }
  10. 定义异常ExceptionAspect(ExceptionAspect的目的是在类ServiceB的方法执行出现异常时收到通知并输出一些信息)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Aspect(Service.class)
    public class ExceptionAspect{
    public static void exception(Object object,
    Method method,Object[] args,Throwalbe e){
    System.out.println("exception when calling"+method.getName()+","+
    Arrays.toString(arts)
    );
    }
    }

    其中LogServiceAspect和ExpectionAspect把并没有改变类ServiceA和ServiceB的本身,本身做的事情是比较通常的,跟业务的逻辑关系不密切,但又想改变ServiceA/ServiceB的行为。这就是AOP。

  11. 定义CGLibContainer
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    public class CGLibContainer {
    //该枚举类分别表示切点调用前,调用后,出现异常时
    public static enum InterceptPoint {
    BEFORE, AFTER, EXCEPTION
    }

    static Class<?>[] aspects = new Class<?>[] { ServiceLogAspect.class, ExceptionAspect.class };
    //表示每个类的每个切点的方法列表
    static Map<Class<?>, Map<InterceptPoint, List<Method>>> interceptMethodsMap = new HashMap<>();

    static {
    init();
    }
    //分析带@Aspect注解的类,并初始化interceptMethodsMap
    private static void init() {
    for (Class<?> cls : aspects) {
    Aspect aspect = cls.getAnnotation(Aspect.class);
    if (aspect != null) {
    Method before = getMethod(cls, "before", new Class<?>[] { Object.class, Method.class, Object[].class });
    Method after = getMethod(cls, "after",
    new Class<?>[] { Object.class, Method.class, Object[].class, Object.class });
    Method exception = getMethod(cls, "exception",
    new Class<?>[] { Object.class, Method.class, Object[].class, Throwable.class });
    Class<?>[] intercepttedArr = aspect.value();
    for (Class<?> interceptted : intercepttedArr) {
    addInterceptMethod(interceptted, InterceptPoint.BEFORE, before);
    addInterceptMethod(interceptted, InterceptPoint.AFTER, after);
    addInterceptMethod(interceptted, InterceptPoint.EXCEPTION, exception);
    }
    }
    }
    }

    private static Method getMethod(Class<?> cls, String name, Class<?>[] paramTypes) {
    try {
    return cls.getMethod(name, paramTypes);
    } catch (NoSuchMethodException e) {
    return null;
    }
    }
    //将方法加入到method列表中
    private static void addInterceptMethod(Class<?> cls, InterceptPoint point, Method method) {
    if (method == null) {
    return;
    }
    Map<InterceptPoint, List<Method>> map = interceptMethodsMap.get(cls);
    if (map == null) {
    map = new HashMap<>();
    interceptMethodsMap.put(cls, map);
    }
    List<Method> methods = map.get(point);
    if (methods == null) {
    methods = new ArrayList<>();
    map.put(point, methods);
    }
    methods.add(method);
    }

    static List<Method> getInterceptMethods(Class<?> cls,
    InterceptPoint point) {
    Map<InterceptPoint, List<Method>> map = interceptMethodsMap.get(cls);
    if (map == null) {
    return Collections.emptyList();
    }
    List<Method> methods = map.get(point);
    if (methods == null) {
    return Collections.emptyList();
    }
    return methods;
    }

    static class AspectInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object object, Method method,
    Object[] args, MethodProxy proxy) throws Throwable {
    //执行before方法
    List<Method> beforeMethods = getInterceptMethods(
    object.getClass().getSuperclass(), InterceptPoint.BEFORE);
    for (Method m : beforeMethods) {
    m.invoke(null, new Object[] { object, method, args });
    }

    try {
    // 调用原始方法
    Object result = proxy.invokeSuper(object, args);

    // 执行after方法
    List<Method> afterMethods = getInterceptMethods(
    object.getClass().getSuperclass(), InterceptPoint.AFTER);
    for (Method m : afterMethods) {
    m.invoke(null, new Object[] { object, method, args, result });
    }
    return result;
    } catch (Throwable e) {
    //执行exception方法
    List<Method> exceptionMethods = getInterceptMethods(
    object.getClass().getSuperclass(), InterceptPoint.EXCEPTION);
    for (Method m : exceptionMethods) {
    m.invoke(null, new Object[] { object, method, args, e });
    }
    throw e;
    }
    }
    }

    private static <T> T createInstance(Class<T> cls)
    throws InstantiationException, IllegalAccessException {
    if (!interceptMethodsMap.containsKey(cls)) {
    return (T) cls.newInstance();
    }
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(cls);
    enhancer.setCallback(new AspectInterceptor());
    return (T) enhancer.create();
    }

    public static <T> T getInstance(Class<T> cls) {
    try {
    T obj = createInstance(cls);
    Field[] fields = cls.getDeclaredFields();
    for (Field f : fields) {
    if (f.isAnnotationPresent(SimpleInject.class)) {
    if (!f.isAccessible()) {
    f.setAccessible(true);
    }
    Class<?> fieldCls = f.getType();
    f.set(obj, getInstance(fieldCls));
    }
    }
    return obj;
    } catch (Exception e) {
    throw new RuntimeException(e);
    }
    }
文章作者: Anders Cao
文章链接: http://yoursite.com/2019/05/06/代理/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Anders's Blog
打赏
  • 微信
  • 支付寶