由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。代理模式范围静态代理和动态代理(JDK代理和CGLib代理)
静态代理:在编译期就生成
- 把需要代理的方法抽出作为接口,目标对象和代理对象都实现这个方法,代理对象聚合目标对象,使用目标对象实现的方法,调用方法之前和之后做一系列的增强
动态代理:在程运行时动态的在内存中生成,对接口进行代理
- jdk动态代理:不定义代理对象,而是定义一个代理对象工厂,工厂中创建一个目标对象,使用Proxy的newProxyInstance来设定代理对象的增强策略,会返回一个代理类,通过get方法获得代理类,之后使用代理类的增强方法
/**
* 需要被代理增强方法
*/
public interface ProxyMethod {
Integer getAge(Integer age);
String getName(String name);
}
/**
* 目标对象 如果有要增强的方法就把他写成一个接口供代理对象和目标对象实现
*/
public class TargetObject implements ProxyMethod{
public Integer getAge(Integer age) {
return age;
}
public String getName(String name) {
return name;
}
}
package com.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* jdk动态代理,代理对象是在运行是动态生成的
* 代理对象工厂,要定义需要被增强的对象
*/
public class ProxyFactory {
//要被增强的对象
private TargetObject targetObject = new TargetObject();
//获得代理对象,代理对象通过匿名内部类生成
public ProxyMethod getProxyObject() {
/**
* 生成的是调用的方法的反射对象,如果一个接口有多个方法,调用了几个就会生成几个动态代理对象,一个代理对象里面只有一个方法
* 代理对象生成的策略 需要
* ClassLoader loader, 类加载器 生成代理对象用
* Class<?>[] interfaces, 代理增强的方法接口字节码 让代理对象可以实现和目标对象一样的接口
* InvocationHandler h 具体的增强策略
*/
ProxyMethod proxyMethod = (ProxyMethod) Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
new InvocationHandler() {
/**
* @param proxy 代理对象
* @param method 调用的方法
* @param args 参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
if ("getName".equals(method.getName())) {
for (Object arg : args) {
arg += "123";
//执行目标对象方法,指定的方法参数被修改了
invoke = method.invoke(targetObject, arg);
}
}else {
invoke = method.invoke(targetObject, args);
}
return invoke;
}
}
);
return proxyMethod;
}
}
ProxyFactory proxyFactory = new ProxyFactory();
ProxyMethod proxyObject = proxyFactory.getProxyObject();
System.out.println(proxyObject.getName("name"));//name123
- cglib动态代理: 不需要定义接口,通过继承来实现增强方法
/**
* cglib动态代理,代理对象是在运行是动态生成的,通过继承的方式,所以不需要接口
* 代理对象工厂,要定义需要被增强的对象
* 需要实现MethodInterceptor接口,重写的方法就是增强方法
*/
public class ProxyFactory implements MethodInterceptor {
//要被增强的对象
private TargetObject targetObject = new TargetObject();
//获得代理对象
public TargetObject getProxyObject() {
Enhancer enhancer = new Enhancer();
//指定要增强的对象
enhancer.setSuperclass(targetObject.getClass());
//设置回调函数,调用代理对象的时候执行,当前类实现了回调
enhancer.setCallback(this);
//创建代理对象
TargetObject o = (TargetObject) enhancer.create();
return o;
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object invoke = null;
if ("getName".equals(method.getName())) {
for (Object arg : objects) {
arg += "123";
//执行目标对象方法,指定的方法参数被修改了
invoke = method.invoke(targetObject, arg);
}
}else {
invoke = method.invoke(targetObject, objects);
}
return invoke;
}
}