代理模式:主要解决的问题是为某些资源的访问、对象的类的易用操作上提供方便使用的代理服务。
使用场景:
- 通过数据库访问层面提供较为基础的应用,来减少服务扩展时数据库连接数陡增的情况。
- 一些中间件:RPC框架。在拿到jar包的接口描述后,中间件在服务启动的时候生成对应的代理类,当调用接口的时候,实际是通过代理类发出socket信息。
- MyBatis,基本是定义接口但是不需要写实现类,就可以对mapper.xml或者注解里的sql语句进行增删改查操作。
结构:
- 抽象主题角色:声明了真实主题和代理主题的共同接口。
- 代理主题角色:内部包含了对真实主题和代理主题的共同接口。
- 真实主题角色:定义真实对象。
Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:
当然你也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。
扩展--Spring AOP 和AspectJ AOP区别
JDK中的动态代理
InvocationHandler中的invoke()方法属于代理类中调用真实主题类的方法,但是该方法没有所对应的真实主题类,需要在创建对象时设置真实主题。
package java.lang.reflect; public interface InvocationHandler { /** * Object proxy:代理类的对象[代理后的类] * Method method:需要调用的方法 * Object[] args:方法所需的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
若要得到代理对象需使用java.lang.reflect.Proxy类动态创建。
/** * ClassLoader loader:取得对象的加载器 * Class<?>[] interfaces:代理模式的核心是围绕接口进行的,所以需取出全部接口 * InvocationHandler h:代理实现类 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
示例一:
// 简单Java类
public class Dept {
}
// 定义的接口层
public interface IDeptDAO {
boolean doCreate(Dept vo) throws Exception;
List<Dept> findAll() throws Exception;
}
// 具体接口实现
public class DeptDAOImpl implements IDeptDAO{
@Override
public boolean doCreate(Dept vo) throws Exception {
System.out.println("执行数据增加操作");
return false;
}
@Override
public List<Dept> findAll() throws Exception {
System.out.println("执行数据查询操作");
return null;
}
}
//动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DAOProxy implements InvocationHandler {
// 不能与具体的DAO耦合在一起
private Object obj ; // 真实主题类--需要代理的
/**
* 将真实主题类绑定到代理中,返回一个被代理后的对象
* @param obj 真实主题类
* @return 代理后的对象
*/
public Object bind(Object obj){
// !!!!要保存真实主题类--便于后面的方法执行!!!!
this.obj = obj ;
/**
* -----由Java系统实现的代理
* obj.getClass().getClassLoader() : 通过反射取得该真实主题类的类加载器
* obj.getClass().getInterfaces() : 通过反射取得真实主题的所有接口
* this: 由于当前DAOProxy实现了InvocationHandler,所以是代理类
*/
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
public void prepare(){
System.out.println("*************取消JDBC的自动提交***************");
}
public void commit(){
System.out.println("*************手动提交JDBC事务***************");
}
public void rollback(){
System.out.println("*************手动回滚JDBC事务***************");
}
// 只要执行了方法,就会触发执行invoke()方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null ; // 接收结果
if (method.getName().contains("do")){
// 取得方法的名称对操作进行判断
this.prepare();
try {
// 反射中的知识--执行方法需要存在类的实例所以要保存this.obj
result = method.invoke(this.obj, args);
this.commit();
} catch (Exception e){
e.printStackTrace();
rollback();
}
} else{
// 如果不需要开启事务,则直接执行方法
result = method.invoke(this.obj, args);
}
return result;
}
}
// 通过工厂类隐藏具体细节
public class DAOFactory {
public static Object getDAOInstance(){
// 直接将真实主题类绑定到代理中返回代理后的类
return new DAOProxy().bind(new DeptDAOImpl());
}
}
//测试类
public class ProxyMain {
public static void main(String[] args) throws Exception{
IDeptDAO dao = (IDeptDAO) DAOFactory.getDAOInstance();
Dept dept = new Dept();
dao.doCreate(dept);
dao.findAll();
}
}
/* output:
* *************取消JDBC的自动提交***************
* 执行数据增加操作
* *************手动提交JDBC事务***************
* 执行数据查询操作
* /
CGLIB动态代理
CGLIB利用这个包可以在没有接口的情况下实现动态代理设计模式
CGLIB是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)
在使用CGLIB时,必须清楚对应关系:
- Proxy -> net.sf.cglib.proxy.Enhancer;
- InvocationHandler -> net.sf.cglib.proxy.MethodInterceptor;
- 真实主题调用:net.sf.cglib.proxy.MethodProxy
package 代理设计模式;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class FunctionImple{
public void create(){
System.out.println("create方法");
}
}
class MyProxy implements MethodInterceptor{
private Object object; // 真实操作主题类
public MyProxy(Object object){
this.object = object;
}
public void prepre(){
System.out.println("取消自动提交");
}
public void commit(){
System.out.println("提交进行事务操作");
}
public void rollback(){
System.out.println("提交失败,回滚");
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object reuslt = null;
// 说明proxy是真实类的子类--如果被代理类是Final类就无法使用CGLIB
// 但是ASM可以对Final进行代理
System.out.println(proxy.getClass().getSuperclass().getName());
this.prepre();
// CGLIB反射调用真实对象方法
reuslt = methodProxy.invokeSuper(proxy, args);
this.commit();
return reuslt;
}
}
public class CGLIBDemo {
public static void main(String[] args) {
// 真实主题对象
FunctionImple functionImple = new FunctionImple();
// CGLIB enhancer增强类对象
Enhancer enhancer = new Enhancer();
// 设置增强类型--是当前类的子类
enhancer.setSuperclass(FunctionImple.class);
// 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
enhancer.setCallback(new MyProxy(functionImple));
// 生成并返回代理对象
FunctionImple proxyDao = (FunctionImple) enhancer.create();
proxyDao.create();
}
}
/**
* 代理设计模式.FunctionImple
* 取消自动提交
* create方法
* 提交进行事务操作
*/