Spring-代理
Spring-代理
存在一个类,实现两个数的加减乘除功能,并想在功能实现的前后加上日志,日志内容为进行了什么操作,输出结果是什么
我们可以在每一个方法中,使用print的方式来打印日志,但这十分麻烦且有大量的冗余代码
使用代理模式来解决这个问题
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);
}
import org.springframework.stereotype.Component;
@Component
public class CalculatorPureImpl implements Calculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
静态代理
新建一个代理类同样实现功能接口,但代理类不做具体的功能实现,只负责日志的打印
将实现类作为代理类的属性,并在构造方法将实现类注入到代理类中
在重写的功能方法中,先打印所需要的日志,再调用实现类中的方法去完成具体的功能实现
public class CalculatorStaticProxy implements Calculator {
Calculator calculator = new CalculatorPureImpl();
public CalculatorStaticProxy(Calculator calculator) {
this.calculator = calculator;
}
@Override
public int add(int i, int j) {
System.out.println("i = " + i + ", j = " + j);
int result = calculator.add(i, j);
System.out.println("result = " + result);
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("i = " + i + ", j = " + j);
int result = calculator.sub(i, j);
System.out.println("result = " + result);
return result;
}
@Override
public int mul(int i, int j) {
System.out.println("i = " + i + ", j = " + j);
int result = calculator.mul(i, j);
System.out.println("result = " + result);
return result;
}
@Override
public int div(int i, int j) {
System.out.println("i = " + i + ", j = " + j);
int result = calculator.div(i, j);
System.out.println("result = " + result);
return result;
}
}
动态代理
JDK动态代理:JDK提供了原生的动态代理的实现方式,他必须需要被代理的实现类的接口,会根据接口动态生成一个代理对象
cglib:第三方技术(被Spring集成),通过被代理的实现类直接生成一个代理类,不需要实现类的接口
JDK动态代理
尚硅谷提供了一个基于JDK动态代理的生成工具类
和静态代理类一样,将实现类对象作为代理类的属性注入,在这里为了实现动态,类的类型是Object
Proxy.newProxyInstance()方法需要三个参数
- classLoader:实现类的类加载器
- interfaces:实现类的接口
- invocationHandler:具体的代理类的功能类,其参数需要重写抽象方法,其中具体的实现使用到反射
- 抽象方法提供了三个参数,proxy(实现类的对象),method(实现类的功能方法),args(方法所对应的参数)
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(){
/**
* newProxyInstance():创建一个代理实例
* 其中有三个参数:
* 1、classLoader:加载动态生成的代理类的类加载器
* 2、interfaces:目标对象实现的所有接口的class对象所组成的数组
* 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法
*/
ClassLoader classLoader = target.getClass().getClassLoader(); // 获取到实现类的类加载器
Class<?>[] interfaces = target.getClass().getInterfaces(); // 获取实现类的接口
InvocationHandler invocationHandler = new InvocationHandler() {
// 通过匿名内部类的方式重写了InvocationHandler的抽象方法invoke
// 这个方法就是代理类具体要做的事
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* proxy:代理对象
* method:代理对象需要实现的方法,即其中需要重写的方法
* args:method所对应方法的参数
*/
Object result = null;
try {
System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
result = method.invoke(target, args);
System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
} catch (Exception e) {
e.printStackTrace();
System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
} finally {
System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
}
return result;
}
};
return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
}
AOP框架就是封装了动态代理技术