设计模式-代理模式
分类:
代理模式通常来说有三种类型,分别是静态代理、JDK动态代理、Cglib代理
代理模式主要功能:
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
简单来说就是屏蔽掉用户的直接操作对象,提供一个第三方api来完成操作。
静态代理DEMO:
接口-抽象类:
public interface IUserDao { void save(); }
实现类:
public class UserDao implements IUserDao { @Override public void save() { System.out.println("数据插入到数据库!"); } }
代理类:
public class DaoProxy implements IUserDao{ private IUserDao userDao; public DaoProxy(IUserDao userDao) { this.userDao=userDao; } @Override public void save() { System.out.println("开启事物"); userDao.save(); System.out.println("关闭事物"); } }
测试:
public class MainTest { public static void main(String[] args){ DaoProxy proxy= new DaoProxy(new UserDao()); proxy.save(); } }
//打印数据
开启事物
数据插入到数据库!
关闭事物
这是静态代理,可以在不修改目标对象代码的情况下,对目标进行扩展。
但是静态代理维护起来比较麻烦,如果在接口中增加方法,实现类与代理类同时需要维护,
并且静态代理基本都是作用于类已知的状态下,目标类是已知才可以使用静态代理,如果目标类很多的话,很多时候就要写很多代理类,这就比较麻烦。
JDK的动态代理:
先来看一下需要用到的类,接上一章反射用到的类
java.lang.reflect.Proxy //Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
看一下这个类的API,有这么一个方法,使用这个方法可以返回代理类的实例;
java.lang.reflect.InvocationHandler //看一下这个接口的api介绍
实现这个类为我们具体执行方法的处理器类。
在接静态代理的基础上,去除掉针对每个目标类的代理类,建立一个类工厂
工厂类:
public class ProxyFactory { //维护一个目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } //给目标对象生成代理对象 public Object getProxyInstance() { Object proxy = null; Class classObj= target.getClass(); //动态代理里面反射是必须的 proxy= Proxy.newProxyInstance(classObj.getClassLoader(),//获取类加载器 classObj.getInterfaces(), new InsertHandler(target)//根据传入的对象创建处理器类 ); return proxy; } }
处理器类:
public class InsertHandler implements InvocationHandler { private Object target; public InsertHandler( Object target) { this.target=target; } @Override 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; } }
测试:
public class MainTest { public static void main(String[] args){ IUserDao target = new UserDao(); IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); proxy.save();//执行这个方法的时候实际上是去执行了代理类中的invoke方法 System.out.println("---------分割线-----------"); proxy.delete(); } }
//打印
开始事物!
数据插入到数据库!
提交事物!
---------分割线-----------
开始事物!
数据库删除数据!
提交事物!
使用jdk的动态代理还是很方便的,不过有个前提条件,就是目标对象一定要实现接口。
Cglib动态代理:
看一下介绍:
CGLIB是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
public class UserDao { public void save() { System.out.println("数据插入到数据库!"); } public void delete() { System.out.println("数据库删除数据!"); } public static void update() { System.out.println("修改数据库数据!"); } public final void finalMethod() { System.out.println("final方法!"); } }
代理工厂类:
public class ProxyFactory implements MethodInterceptor { private Object target; //维护一个目标对象 public ProxyFactory(Object target) { this.target = target; } /** * 给目标对象创建一个代理对象 * @return */ public Object getProxyInstance() { Enhancer en = new Enhancer(); en.setSuperclass(target.getClass()); en.setCallback(this); return en.create(); } /** * 用于目标方法 * @return */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("开始事务"); Object invoke = method.invoke(target, objects); System.out.println("提交事务"); return invoke; } }
测试:
public class MainTest { public static void main(String[] args) { UserDao userDao = new UserDao(); UserDao proxy = (UserDao) new ProxyFactory(userDao).getProxyInstance(); proxy.save(); System.out.println("--------分割线---------"); proxy.delete(); System.out.println("--------分割线---------"); proxy.finalMethod(); } }
//打印
开始事务
数据插入到数据库!
提交事务
--------分割线---------
开始事务
数据库删除数据!
提交事务
--------分割线---------
final方法!