代理模式定义:为其他对象提供一种代理以控制对这个对象的访问
通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
静态代理:在编译时就已经将接口、被代理类、代理类等确定下来。
interface ShoppingService {
void go();
}
public static class ShoppingServiceImpl implements ShoppingService {
@Override
public void go () {
System.out.println("正在购物呢");
}
}
public static class ShoppingServiceProxy implements ShoppingService {
private final ShoppingService service;
public ShoppingServiceProxy (ShoppingService service) {
this.service = service;
}
@Override
public void go () {
System.out.println("准备去购物啦");
service.go();
System.out.println("购物完回家咯");
}
}
public static void main (String[] args) {
// 真实对象
ShoppingService service = new ShoppingServiceImpl();
// 代理对象
ShoppingServiceProxy serviceProxy = new ShoppingServiceProxy(service);
serviceProxy.go();
}
缺点:代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护
动态代理:在编译期间无法确定需要代理的类。运行期间动态生成代理类
JDK动态代理是通过重写被代理对象实现的接口中的方法来实现
interface ShoppingService {
void go();
}
public static class ShoppingServiceImpl implements ShoppingService {
@Override
public void go () {
System.out.println("正在购物呢");
}
}
public static class DynamicProxy implements InvocationHandler{
// 真实代理对象 -> Service 实现类
private final Object service;
// DynamicProxy 代理 Service 实现类
public DynamicProxy (Object service) {
this.service = service;
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("准备去购物啦");
method.invoke(service, args);
System.out.println("购物完回家咯");
return null;
}
}
public static void main (String[] args) {
// 真实对象
ShoppingService service = new ShoppingServiceImpl();
// 代理对象
InvocationHandler handler = new DynamicProxy(service);
ShoppingService serviceProxy = (ShoppingService) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), handler);
serviceProxy.go();
}
jdk动态代理只能基于接口进行代理(因为代理对象已经继承了proxy了)
CGLIB是通过继承被代理对象来实现
interface ShoppingService {
void go();
}
public static class ShoppingServiceImpl implements ShoppingService {
@Override
public void go () {
System.out.println("正在购物呢");
}
}
public static class MyInterceptor implements MethodInterceptor {
private Object target;
public MyInterceptor(Object object){
this.target = object;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib before!");
Object invoke = methodProxy.invoke(target, objects);
System.out.println("cglib after!");
return invoke;
}
}
public static void main (String[] args) {
// 真实对象
ShoppingService service = new ShoppingServiceImpl();
MyInterceptor interceptor = new MyInterceptor(service);
//通过 CGLIB 动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
//设置父类,因为 cglib 是针对指定的类生成一个子类,所以需要父类
enhancer.setSuperclass(ShoppingServiceImpl.class);
//设置回调
enhancer.setCallback(interceptor);
//生成代理对象
ShoppingServiceImpl actorProxy = (ShoppingServiceImpl)enhancer.create();
}
两种方式的区别:
JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。