java设计模式-代理模式.md

java设计模式-代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

静态代理

静态代理其实挺简单的,我们把真正要实现功能的对象称作目标对象,实现代理功能的对象称作代理对象。在我们这个例子中,要实现的功能是在userDao中保存数据。

首先有一个接口userDao,目标对象UserDaoImpl和代理对象UserDaoProxy都实现了这个接口。这样也保证了两个类都会有同名的方法(这里姑且叫做代理方法好了)。既然是代理,那么代理对象首先要和目标对象有联系,所以代理类里面引用了目标对象。当我们要调用目标对象的代理方法时,实际上是通过调用代理对象的代理方法,代理对象的代理方法中再去调用目标对象的代理方法,这种间接调用的方法实现的。下面来看看代码:

UserDao.java 接口

public interface UserDao {
	void save();
}

UserDaoImpl.java 目标对象

public class UserDaoImpl implements UserDao {
	@Override
	public void save() {
		System.out.println("----保存数据成功------");
	}
}

UserDaoProxy.java 代理对象

public class UserDaoProxy implements UserDao {
	UserDao userDao = null;
	public UserDaoProxy(UserDao userDao) {
		this.userDao = userDao;
	}
	@Override
	public void save() {
		System.out.println("----开始事务----");
		userDao.save();
		System.out.println("----结束事务----");
	}
}

调用

	public static void main(String[] args) {
		UserDaoImpl userDaoImpl = new UserDaoImpl();
        //将目标对象传给代理对象
		UserDaoProxy userDaoProxy = new UserDaoProxy(userDaoImpl);
		userDaoProxy.save();
	}

打印结果

----开始事务----
----保存数据成功------
----结束事务----

可以看到,代理模式可以做到控制对一个对象的访问,在访问的前后可以做一些其他事项。静态方法的不足就是都是代码都是写死的,如果要增加一个代理方法,那么很多地方都要改变,所以就有了动态代理。

动态代理

动态代理主要来看看Jdk动态代理和Cglib动态代理,Spring和AspectJ的动态代理是基于前面两种来实现的。

jdk代理

jdk代理用到了java.lang.reflect.Proxy这个类,当中有一个方法

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

这个方法返回了一个代理对象,这是一个什么代理对象呢?你可以指定它的类加载器,指定它实现的接口,指定它的调用处理器(分别是传入的三个参数)。

我们的目标对象还是实现了一个接口,这个没有变化,我们的代理类就不需要自己去实现接口了,因为前面提到的newProxyInstance方法已经帮我们指定它的接口了。所以我们调用newProxyInstance()这个方法,就可以返回代理对象了。

我们来一个代理工厂,负责生产代理对象。

ProxyFactory.java

public class ProxyFactory{
    //这里维护目标对象
	private UserDao userDao = null;
	public ProxyFactory(UserDao userDao) {
		this.userDao = userDao;
	}
	
    //获得代理对象
	public Object getProxyInstance() {
		return Proxy.newProxyInstance(userDao.getClass().getClassLoader(), 
								userDao.getClass().getInterfaces(), 
								new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("开始事务");
				Object invoke = method.invoke(userDao, args);
				System.out.println("结束事务");
				return invoke;
			}
		});
	}
}

调用

	public static void main(String[] args) {
		UserDaoImpl userDaoImpl = new UserDaoImpl();
		UserDao proxyInstance = (UserDao) new ProxyFactory(userDaoImpl).getProxyInstance();
		proxyInstance.save();
	}

打印

开始事务
----保存数据成功------
结束事务

cglib代理

jdk动态代理要求被代理的对象必须要实现一个接口,如果没有实现接口就无法使用jdk动态代理。而cglib就不需要实现接口,cglib代理也叫子类代理,是通过被代理对象的子类,覆盖其中的方法实现增强,由于用的是继承, 所以不能对final修饰的对象进行代理。

UserDao.java–现在的目标对象,不需要继承接口

public class UserDao  {
	public void save() {
		System.out.println("----保存数据成功------");
	}
}

ProxyFactory.java

public class ProxyFactory{
	private UserDao userDao = null;
	public ProxyFactory(UserDao userDao) {
		this.userDao = userDao;
	}
	
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(userDao.getClass());
        //3.设置回调函数
        en.setCallback(new MethodInterceptor() {
			
			@Override
			public Object intercept(Object object, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
				System.out.println("开始事务");
				Object invoke = method.invoke(userDao, arg2);
				System.out.println("关闭事务");
				return invoke;
			}
		});
        //4.创建子类(代理对象)
        return en.create();
    }

}

调用

	public static void main(String[] args) {
		UserDao userDao = new UserDao();;
		UserDao proxyInstance = (UserDao) new ProxyFactory(userDao).getProxyInstance();
		proxyInstance.save();
		if( proxyInstance instanceof UserDao) {
			System.out.println("yes");
		}
	}

这里我判断了一下代理对象是不是目标对象的子类。

打印结果

开始事务
----保存数据成功------
关闭事务
yes

我们来看看ProxyFactory.java中的 en.setCallback()这个方法。这里面的MethodInterceptor是一个接口,根据名字可以知道这是一个方法拦截器,可以看到这个接口里的intercept方法和前面jdk代理里面的invoke方法有点类似。

所以如果有接口可以使用jdk代理,没有接口则使用cglib代理,这也是spring中的策略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值