AOP的代理模式

47 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

AOP

代理模式

场景模拟

接口类

public interface Calculator {
​
     int add(int i ,int j);
​
     int sub(int i ,int j);
​
     int mul(int i ,int j);
​
     int div(int i ,int j);
}

实现类

在四个方法中模拟了日志功能,但这些日志并不是add方法的核心业务功能,这就会导致一些问题:

  • 对核心业务功能有千扰。导致程序员在开发核心业务功能时分散了精力
  • 附加功能分散在各个业务功能方法中,不利于统—维护
package com.sentiment.proxy;
​
public class CalculatorImpl implements Calculator {
​
    @Override
    public int add(int i, int j) {
        System.out.println("日志,方法:add,参数"+i+","+j);
        int result=i+j;
        System.out.println("方法内部,result:"+result);
        System.out.println("日志,方法:add,结果"+i+","+j);
        return result;
    }
​
    @Override
    public int sub(int i, int j) {
        System.out.println("日志,方法:sub,参数"+i+","+j);
        int result=i-j;
        System.out.println("方法内部,result:"+result);
        System.out.println("日志,方法:sub,结果"+i+","+j);
        return result;
    }
​
    @Override
    public int mul(int i, int j) {
        System.out.println("日志,方法:mul,参数"+i+","+j);
        int result=i*j;
        System.out.println("方法内部,result:"+result);
        System.out.println("日志,方法:mul,结果"+i+","+j);
        return result;
    }
​
    @Override
    public int div(int i, int j) {
        System.out.println("日志,方法:div,参数"+i+","+j);
        int result=i/j;
        System.out.println("方法内部,result:"+result);
        System.out.println("日志,方法:div,结果"+i+","+j);
        return result;
    }
}

静态代理

通过上例就引出了代理模式,即:各自的方法由自己来实现就好,附加功能由代理来实现

将CalculatorImpl中的日志功能部分除去,加到代理类中

代理类

package com.sentiment.proxy;
​
public class CalculatorStiaticProxy implements Calculator {
    private CalculatorImpl target;
​
    public CalculatorStiaticProxy(CalculatorImpl target) {
        this.target = target;
    }
​
    @Override
    public int add(int i, int j) {
        System.out.println("日志,方法:add,参数"+i+","+j);
        int result = target.add(i,j);
        System.out.println("日志,方法:add,结果"+i+","+j);
        return result;
    }
​
    @Override
    public int sub(int i, int j) {
        System.out.println("日志,方法:sub,参数"+i+","+j);
        int result = target.sub(i,j);
        System.out.println("日志,方法:sub,结果"+i+","+j);
        return result;
    }
​
    @Override
    public int mul(int i, int j) {
        System.out.println("日志,方法:mul,参数"+i+","+j);
        int result = target.sub(i,j);
        System.out.println("日志,方法:mul,结果"+i+","+j);
        return result;
    }
​
    @Override
    public int div(int i, int j) {
        System.out.println("日志,方法:div,参数"+i+","+j);
        int result = target.sub(i,j);
        System.out.println("日志,方法:div,结果"+i+","+j);
        return result;
    }
}

测试类

public void testProxy(){
    CalculatorStiaticProxy proxy = new CalculatorStiaticProxy(new CalculatorImpl());
    proxy.add(1,2);
}

动态代理

静态代理代理类和业务类都需要实现同样的接口,会造成代码的重复并且静态代理缺乏一定的灵活性,因此引出了动态代理。

动态代理主要涉及java.lang.reflect包下的Proxy类和InvocationHandler接口。

先看下java.lang.reflect.Proxy类,其中有个newProxyInstance就是实现动态代理的方法

package java.lang.reflect;
​
import java.lang.reflect.InvocationHandler;
​
public class Proxy implements java.io.Serializable {
​
    public static Object newProxyInstance(ClassLoader loader,
                                            Class<?>[] interfaces,
                                            InvocationHandler h)
                            
        ..........
​
}
  • classLoader Loader:指定加载动态生成的代理类的类加载器
  • class[] interfaces:获取目标对象实现的所有接口的class对象的数组
  • invocationHandler h:设置代理类中的抽象方法如何重写

重点在invocationHandler h,该类只有一个方法

public interface InvocationHandler {
​
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
​
  • proxy 代理对象
  • method 要调用的代理对象方法
  • args 要调用方法的参数

代理类

package com.sentiment.proxy;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
​
public class ProxyFactory {
    private Object target;
​
    public ProxyFactory(Object target) {
        this.target = target;
    }
​
    public Object getProxy(){
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler h = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("日志参数:" + Arrays.toString(args));
                Object result = method.invoke(target, args);
                System.out.println("日志结果:" + result);
                return result;
            }
        };
        return Proxy.newProxyInstance(classLoader,interfaces,h);
    }
}

测试

import com.sentiment.proxy.Calculator;
import com.sentiment.proxy.CalculatorImpl;
import com.sentiment.proxy.CalculatorStiaticProxy;
import com.sentiment.proxy.ProxyFactory;
import org.junit.Test;
​
public class ProxyTest {
    @Test
    public void dynamicProxy(){
        ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());
        Calculator proxy = (Calculator) proxyFactory.getProxy();
        proxy.add(1,2);
    }
}