什么是代理模式(Proxy)
定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
在代理模式中,是需要代理对象和目标对象实现同一个接口
为什么要用代理
最最最主要的原因就是,在不改变目标对象方法的情况下对方法进行增强,比如,我们希望对方法的调用增加日志记录,或者对方法的调用进行拦截,等等...
一:JDK动态代理
JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。
案例
1、定义业务接口以及实现类
package com.yjc.jdkproxy;
public interface DoSomeService {
void doSome();
}
-------------------------------------------
package com.yjc.jdkproxy;
public class DoSomeServiceImpl implements DoSomeService {
@Override
public void doSome() {
System.out.println("doSome++++++++++++++++++==");
}
}
2.调用管理接口InvocationHandler 创建动态代理类
package com.yjc.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DoSomeHandler implements InvocationHandler {
//这其实业务实现类对象,用来调用具体的业务方法
private Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before----------------------------"); //调用真正的业务方法
Object invoke = method.invoke(target, args);
System.out.println("after---------------------------");
return invoke;
}
public DoSomeHandler(Object target) {
this.target = target;//接收业务实现类对象参数
}
public DoSomeHandler() {
}
}
测试方法
package com.yjc.jdkproxy;
import sun.misc.ProxyGenerator;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
public class JdkProxyTest {
public static void main(String[] args) throws IOException {
DoSomeService doSomeService=new DoSomeServiceImpl(); //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
DoSomeService o = (DoSomeService)Proxy.newProxyInstance(doSomeService.getClass().getClassLoader(), new Class[]{DoSomeService.class}, new DoSomeHandler(doSomeService));
//调用目标函数 o.doSome(); //将内存中代理的类生成到本地
byte[] $proxy0s = ProxyGenerator.generateProxyClass("$proxy0", new Class[]{DoSomeService.class});
FileOutputStream fos=new FileOutputStream("F:/$proxy0.class");
fos.write($proxy0s);
fos.flush();
fos.close();
}
}
二:CGLIB动态代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
cglib和jdk动态代理的区别就是,cglib无需业务接口也可以实现动态代理,而jdk是在业务接口的基础上进行实现的,没有接口不行。cglib也需要项目对cglib的支持,需要引入依赖
业务类
package com.yjc.cglibproxy;
public class DoSomeServiceImpl {
public void doSome() {
System.out.println("doSome++++++++++++++++++==");
}
}
代理类
package com.yjc.cglibproxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DoSomeHandler implements MethodInterceptor {
//目标对象
private Object target;
public DoSomeHandler(Object target) {
this.target = target;
}
public DoSomeHandler() {
}
/**
*
* 方法描述 当对基于代理的方法回调时,在调用原方法之前会调用该方法
* 拦截对目标方法的调用
*
* @param obj 代理对象
* @param method 拦截的方法
* @param args 拦截的方法的参数
* @param proxy 代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before==========================");
Object invoke = method.invoke(target, objects);
System.out.println("after============================");
return invoke;
}
}
测试类
package com.yjc.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyTest {
public static void main(String[] args) {
Enhancer enhancer=new Enhancer();
// 设置目标对象的Class
enhancer.setSuperclass(DoSomeServiceImpl.class);
// 设置回调操作,相当于InvocationHandler
enhancer.setCallback(new DoSomeHandler(new DoSomeServiceImpl())); DoSomeServiceImpl o =(DoSomeServiceImpl) enhancer.create(); o.doSome(); } }