应用场景
Proxy代理模式是一种结构型设计模式,主要解决的问题是:直接访问对象时带来的问题。
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者并无区别。
代理类种类:
静态代理:创建代理类再对其编译,在程序运行前代理类的.class文件就已经存在了。
动态代理:在程序运行时运用反射机制动态创建而成。
一、静态代理
静态代理实现很简单,就是跟目标类实现同样的接口,然后引入目标类。在目标类方法执行前后增加额外的方法即可。
但是有个问题需要注意:每次在接口中添加一个新方法,则需要在目标对象中实现这个方法,并且在代理对象中实现相应的代理方法。
public interface ProductDao {
//添加商品
void add();
//删除商品
void delete();
//修改商品
void update();
//查找商品
void select();
}
public class ProductDaoImpl implements ProductDao {
@Override
public void add() {
System.out.println("目标对象中添加商品");
}
@Override
public void delete() {
System.out.println("目标对象中删除商品");
}
@Override
public void update() {
System.out.println("目标对象中修改商品");
}
@Override
public void select() {
System.out.println("目标对象中查找商品");
}
}
public class ProductDaoImplProxy implements ProductDao {
private ProductDao productDao;
public ProductDaoImplProxy(ProductDao productDao) {
super();
this.productDao = productDao;
}
@Override
public void add() {
System.out.println("添加商品begin");
productDao.add();
}
@Override
public void delete() {
System.out.println("刪除商品begin");
productDao.delete();
}
@Override
public void update() {
System.out.println("修改商品begin");
productDao.update();
}
@Override
public void select() {
System.out.println("查找商品begin");
productDao.select();
}
}
执行结果:
二、动态代理
常见的动态代理有JDK动态代理跟Cglib动态代理
1.JDK动态代理
JDK的动态代理,是使用反射技术获得类的加载器并且创建实例,根据类执行的方法在执行方法的前后发送通知。
java.lang.reflect 包下面的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
在代理对象Proxy的新建代理实例方法中,必须要获得类的加载器、类所实现的接口、还有一个拦截方法的句柄。然后在句柄的invoke()方法中调用method.invoke(),在此方法前后发送通知,实现功能扩展。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProductDaoJDKProxy {
public static void main(String[] args) {
//目标对象
ProductDao productDao = new ProductDaoImpl();
//代理对象
ProductDao proxy = (ProductDao) Proxy.newProxyInstance(
productDao.getClass().getClassLoader(),
productDao.getClass().getInterfaces(),
new InvocationHandler() {
//拦截到目标对象的方法时执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk在代理对象中拦截到方法:" + method.getName());
proxy = method.invoke(productDao, args);
return proxy;
}
});
//代理对象调用方法
proxy.add();
proxy.delete();
}
}
运行结果:
2.Cglib动态代理
JDK动态代理和静态代理所代理的类都是实现了某接口的,对于没有实现接口的类,可以使用Cglib动态代理。
Cglib动态代理需要引入两个jar包:asm跟cglib
CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
注意:arg0:生成的代理对象;arg1:目标对象的方法;arg2:目标对象的方法入参
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class ProductDaoCglibProxy {
public static void main(String[] args) {
ProductDaoImpl target = new ProductDaoImpl();
Enhancer enhancer = new Enhancer();
// 设置代理对象的父类
enhancer.setSuperclass(target.getClass());
// 设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("Cglib在代理对象中拦截到方法:" + arg1.getName());
arg0 = arg1.invoke(target, arg2);
return arg0;
}
});
// 代理对象调用方法
ProductDaoImpl proxy = (ProductDaoImpl) enhancer.create();
proxy.add();
proxy.delete();
}
}
运行结果: