持续创作,加速成长!这是我参与「掘金日新计划 · 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);
}
}