代理模式:为对象提供一个替身,以控制这个对象的访问,即通过代理对象访问目标对象。
这样的好处是:可以在目标对象实现的基础上,增强额外的功能操作。
代理模式有三种:静态代理、动态代理和cglib代理
静态代理:
静态代理在使用的时候需要定义接口或者父类,被代理对象和代理对象一起实现相同的接口和继承相同的父类。
案例:
//接口
public interface ITeacherDao {
void teach();
}
//被代理对象
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println("上课");
}
}
//代理对象
public class TeachProxy implements ITeacherDao {
private ITeacherDao iTeacherDao;
public TeachProxy(ITeacherDao iTeacherDao) {
this.iTeacherDao = iTeacherDao;
}
@Override
public void teach() {
System.out.println("开始代理");
iTeacherDao.teach();
System.out.println("结束代理");
}
}
//客户端调用
public class Client {
public static void main(String[] args) {
TeachProxy teachProxy=new TeachProxy(new TeacherDao());
teachProxy.teach();
}
}
类图
静态代理的缺点是代理类和委托类使用了相同的接口,如果接口增加了一个方法,那么代理类和委托类都要同时实现,维护麻烦。
还有一个缺点就是一个代理类只能代理一个类,如果需要代理其他类必须创建新的代理类。如果要为多个类都提供相同的增强,那么静态代理就无法胜任了。
动态代理
不需要实现接口,但是目标对象要实现接口。代理对象的生成是利用JDK的API,动态的在内存中构建代理对象。
public interface ITeacherDao {
void teach();
}
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println("上课");
}
}
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
/*
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
1、ClassLoader loader:指定当前目标使用的类加载器
2、Class<?>[] interfaces:目标对象的接口类型,使用泛型来确认类型
3、InvocationHandler h:对象处理,执行目标对象的方法时,会触发事件处理器方法,会把当前目标方法作为参数传入
*/
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始");
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理结束");
return returnVal;
}
}
);
}
}
cglib代理
cglib代理的目标对象只是一个单独的对象,没有使用任何接口。
代码实现
首先在maven中引入cglib的坐标
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
目标类
public class TeacherDao {
public void teach(){
System.out.println("上课(cglib)");
}
}
代理类,主要有获取代理对象的方法和需要重写intercept方法,intercept方法的内容是对目标方法进行增强。
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//返回代理对象
public Object getProxyInstance(){
//1、创建工具类
Enhancer enhancer=new Enhancer();
//2、设置父类
enhancer.setSuperclass(target.getClass());
//3、设置回调函数
enhancer.setCallback(this);
//4、创建子类对象即代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理开始");
method.invoke(target,objects);
System.out.println("cglib代理结束");
return null;
}
客户端调用
public class Client {
public static void main(String[] args) {
TeacherDao teacherDao=new TeacherDao();
ProxyFactory proxyFactory=new ProxyFactory(teacherDao);
//获取代理对象
TeacherDao proxyInstance= (TeacherDao) proxyFactory.getProxyInstance();
//执行代理对象的方法,将触发intercept
proxyInstance.teach();
}
}