什么是代理模式
代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理模式通俗来讲就是我们生活中常见的中介。
什么是动态代理?
动态代理就是在程序运行期间 通过java的反射机制,创建出代理类对象
动态代理的优点:
在需要代理多个类时,动态代理只需创建一个统一的代理类,而不必像静态代理那样,需要为每个包含业务逻辑的类单独创建代理类。
JDK实现动态代理
使用JDK动态代理步骤
①创建被代理的接口和类;
②创建InvocationHandler接口的实现类,在invoke方法中实现代理逻辑;
③通过Proxy的静态方法newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)
创建一个代理对象
④使用代理对象。
创建InvocationHandler接口的实现类
package com.demo.design_patterns.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TransactionInvocationHandler implements InvocationHandler{
private Object target;
public TransactionInvocationHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行代理方法前的处理");
Object invoke = method.invoke(target, args);
System.out.println("执行代理方法后的处理");
return invoke;
}
/**
* Proxy类:核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法()
* 现在我们是使用Proxy类的方法,代替new的使用。
*
* 方法: 静态方法 newProxyInstance()
* 作用是: 创建代理对象, 等同于静态代理中的TaoBao taoBao = new TaoBao();
* 参数:
* ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader
* 类a , a.getCalss().getClassLoader(), 目标对象的类加载器
* Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
* InvocationHandler h : 就是当前的这个类
* @return
*/
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
}
创建一个方便操作的工厂类
package com.demo.design_patterns.proxy;
public interface ProxyFactory {
public static Object getService(Object service){
//这里返回的是代理类对象
return new TransactionInvocationHandler(service).getProxy();
}
}
执行结果
Cglib动态代理
cglib动态代理和jdk动态代理的区别: jdk动态代理必须要求被代理类实现了某个接口,而cglib无此要求
代码实现
创建一个类实现了MethodInterceptor接口
package com.demo.design_patterns.proxy.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class LogInterceptor implements MethodInterceptor {
/**
* @param obj 表示要进行增强的对象
* @param method 表示拦截的方法
* @param objects 数组表示参数列表,基本数据类型需要传入其包装类型,如int-->Integer、long-Long、double-->Double
* @param methodProxy 表示对方法的代理,invokeSuper方法表示对被代理对象方法的调用
* @return 执行结果
* @throws Throwable 异常
*/
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("登录前的处理");
// 注意这里是调用invokeSuper而不是invoke,否则死循环;
// methodProxy.invokeSuper执行的是原始类的方法;
// method.invoke执行的是子类的方法;
Object result = methodProxy.invokeSuper(obj, objects);
System.out.println("登录后的处理");
return result;
}
}
package com.demo.design_patterns.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
public class CglibFactory {
public static <T extends MethodInterceptor> Object get(Class proxy, T interceptor) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(proxy);
enhancer.setCallback(interceptor);
return enhancer.create();
}
}
执行结果