设计模式——代理模式

代理模式就是给一个对象提供一个代理对象,让该代理对象来控制对原对象的引用,比如买车去4s店,而不是去汽车厂,4s就起到一个代理的作用。

1.静态代理

代理类实现一个接口,之后实现该接口的其他类就可在该代理类中被增强,具有通用性。 如下:

java 复制代码
/*
   抽象用户操作定义
 */
public interface UserDao {

       void saveUser();

}
java 复制代码
/*
   普通用户实现类
 */
public class UserDaoImpl implements UserDao {

    @Override
    public void saveUser() {
        System.out.println("普通用户实现");
    }

}
java 复制代码
/*
  静态代理类
 */
public class StaticProxy  implements UserDao{

    UserDao userDao;

    public StaticProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void saveUser() {
        System.out.println("保存日志");
         try {
             userDao.saveUser();
         }catch (Exception e){
             System.out.println("保存日志");
         }finally {
             System.out.println("保存日志");
         }
        System.out.println("保存日志");
    }

}
java 复制代码
public class Test {
    public static void main(String[] args) {
        //具体对象
        UserDao userDao = new UserDaoImpl();
        StaticProxy staticProxy = new StaticProxy(userDao);
        staticProxy.saveUser();
    }
}

创建静态代理类的对象,将我们创建的普通对象作为参数传入,之后调用代理类中的saveUser()方法,就起到了增强的作用,缺点就是一个代理类只能代理一个接口,而且接口如果有所修改,代理类也要同步修改。

2.动态代理

2.1JDK代理

JDK代理是通过反射来获取代理对象的,通过reflect.Proxy来实现,通过固定的规则生成。如下:

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
   动态代理类
      代理类不需要实现与目标类相同的接口,这样就可以代理任意的目标类
      但是是有要求的,目标类必需实现接口,此种方式是动态代理的实现方式之一: 
        jdk代理 是一种纯反射机制实现(动态获取目标类接口方法)

 */
public class DynamicProxy implements InvocationHandler {

    Object object;//真实对象,接收任何的目标类对象

    public DynamicProxy(Object object) {
        this.object = object;
    }

    /*
           在代理类中调用目标类中的具体方法,
           动态的将代理动态对象,目标类中要调用的方法,及方法中的参数传递过来
           Method method  就是动态获取的真正要执行的方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("之前开启事务");
        method.invoke(object);
        System.out.println("之后提交事务");
        return proxy;
    }

    //真正意义上,运行时生成代理对象的方法,需要被代理类的类加载器,类实现的接口
    public Object getProxy(){
          return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

}
java 复制代码
public class Test {

    public static void main(String[] args) {

          UserDaoImpl userDao = new UserDaoImpl();
          DynamicProxy dtproxy =  new DynamicProxy(userDao);//自己创建的代理类对象
          //这才是真正的创建动态代理对象
          UserDao userDao =    (UserDao)dtproxy.getProxy();
          userDao.saveUser();//使用代理对象调用接口中的方法,获取当前调用的方法,最终调用invoke方法

    }
}

JDK代理的致命缺陷就是被代理的目标类必须实现接口

2.2Cglib代理

Cglib代理很好的解决了目标类无接口实现的情况,Cglib底层采用了字节码的方式给目标类创建了一个子类 ,在子类中采用方法拦截的方式拦截父类的方法调用,然后使用横切的思想去增强

java 复制代码
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


/*
 * 动态代理类
 */
public class CGLibProxy implements MethodInterceptor {
    
	    private Enhancer enhancer = new Enhancer();
	    
	    public Object getProxy(Class<?> clazz){  
	        enhancer.setSuperclass(clazz);  
	        enhancer.setCallback(this);  
	        return enhancer.create();  
	    }  
	    /*
	     * 拦截所有目标类方法的调用 
	     * 参数: 
	     * obj  目标实例对象 
	     * method 目标方法的反射对象 
	     * args 方法的参数 
	     * proxy 代理类的实例 
	     */  
	    public Object intercept(Object obj, Method method, Object[] args,  
	            MethodProxy proxy) throws Throwable {
	        //代理类调用父类的方法  
	        System.out.println("开始事务");  
	        Object obj1 = proxy.invokeSuper(obj, args);  
	        System.out.println("关闭事务");  
	        return obj1;  
	    }
}
java 复制代码
public class Test {

	 public static void main(String[] args) {
    	CGLibProxy proxy = new CGLibProxy();  
		UserDaoImpl userDaoImpl = (UserDaoImpl)proxy.getProxy(UserDaoImpl.class);
		userDaoImpl.save();
	}
}

需要注意的是,如果使用Cglib代理,那么目标类不能被final修饰,目标类中的方法不能被final或static修饰,虽然Cglib方式创建的代理对象性能功能比JDK方式创建的代理对象性能好,但是相应的花费的时间也多,所以对于单例的,Cglib方式比较合适。

相关推荐
In_life 在生活3 小时前
设计模式(四)装饰器模式与命令模式
设计模式
瞎姬霸爱.3 小时前
设计模式-七个基本原则之一-接口隔离原则 + SpringBoot案例
设计模式·接口隔离原则
鬣主任4 小时前
Spring设计模式
java·spring boot·设计模式
程序员小海绵【vincewm】6 小时前
【设计模式】结合Tomcat源码,分析外观模式/门面模式的特性和应用场景
设计模式·tomcat·源码·外观模式·1024程序员节·门面模式
丶白泽6 小时前
重修设计模式-行为型-命令模式
设计模式·命令模式
gjh120810 小时前
设计模式:工厂方法模式和策略模式
设计模式·工厂方法模式·策略模式
shinelord明11 小时前
【再谈设计模式】抽象工厂模式~对象创建的统筹者
数据结构·算法·设计模式·软件工程·抽象工厂模式
前端拾光者12 小时前
前端开发设计模式——责任链模式
设计模式·责任链模式
liang899913 小时前
设计模式之策略模式(Strategy)
设计模式·策略模式
马剑威(威哥爱编程)14 小时前
读写锁分离设计模式详解
java·设计模式·java-ee