Java动态代理的实现

    代理模式可以控制外界对对象的访问,在对象类型一样的情况下添加部分的中间操作,springaop是使用动态代理的一个应用实例。动态代理的实现方式有好几种,这里暂且只是贴出jdk自带的InvocationHandler、cglib,Javassist功能很强大,这里暂且没有例子。jdk的动态代理是依靠接口实现,如果类没有实现接口,则应当使用cglib实现,使用javassist直接创建一个类实现接口,为 实现类添加代码等也是可以的。

    1.InvocationHandler

    InvocationHandler的这个例子是HeadFirst设计模式中的PersonBean保护代理例子。OwnerInvocationHandler阻止Owner代理对象调用setHorOrNotRating方法,而NonOwnerInvocationHandler定义了可以调用NonOwner代理的setHotOrNotRating,但不能调用其他的set方法,代理方法主要通过Java的反射实现。

public class GetProxy {

	public static PersonBean getOwnerProxy(PersonBean personBean) {
		return (PersonBean) Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
				personBean.getClass().getInterfaces(), new OwnerInvocationHandler(personBean));
	}
	public static PersonBean getNonOwnerProxy(PersonBean personBean) {
		return (PersonBean) Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
				personBean.getClass().getInterfaces(), new NonOwnerInvocationHandler(personBean));
	}
}
public class OwnerInvocationHandler implements InvocationHandler {

	private PersonBean personBean;

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		String methodName = method.getName();
		try {
			if (methodName.startsWith("get")) {
				return method.invoke(personBean, args);
			} else if (methodName.equals("setHotOrNotRating")) {
				throw new IllegalAccessException();
			} else if (methodName.startsWith("set")) {
				return method.invoke(personBean, args);
			}
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null;
	}

	public OwnerInvocationHandler(PersonBean personBean) {
		super();
		this.personBean = personBean;
	}

}
public class NonOwnerInvocationHandler implements InvocationHandler {

	private PersonBean personBean;

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		String methodName = method.getName();
		try {
			if (methodName.startsWith("get")) {
				return method.invoke(personBean, args);
			} else if (methodName.equals("setHotOrNotRating")) {
				return method.invoke(personBean, args);
			} else if (methodName.startsWith("set")) {
				throw new IllegalAccessException();
			}
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null;
	}

	public NonOwnerInvocationHandler(PersonBean personBean) {
		super();
		this.personBean = personBean;
	}

}

    2.cglib

    同样来为PersonBeanImpl生成一个代理,这个也是在执行方法前通过方法名判断而进行访问的控制。这个是参考https://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/

class MyInterceptor implements MethodInterceptor {

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		String methodName = method.getName();
		if (methodName.equals("setHotOrNotRating")) {
			throw new IllegalAccessException();
		}
		Object rvt = proxy.invokeSuper(obj, args);
		return rvt;
	}
}
public class PersonBeanProxyFactory {

	@SuppressWarnings("unchecked")
	public static <T> T getAuthInstance(Class<T> t) {
		Enhancer en = new Enhancer();
		// 设置要代理的目标类
		en.setSuperclass(t);
		// 设置要代理的拦截器
		en.setCallback(new MyInterceptor());
		// 生成代理类的实例
		return (T) en.create();
	}
}
public class TestCGLIB {
	public static void main(String[] args) {

		PersonBean jeo = new PersonBeanImpl();
		jeo.setName("joe");
		jeo.setHotOrNotRating(10);
		PersonBean personBean = PersonBeanProxyFactory.getAuthInstance(PersonBeanImpl.class);
		personBean.setName("lusi");
		System.out.println("owner is : " + personBean.getName());
		try {
			personBean.setHotOrNotRating(10);
		} catch (Exception e) {
			System.out.println("set rating error");
		}
		System.out.println("rating is : " + personBean.getHotOrNotRating());
	}
}

    上面的两个都是简单通过方法名控制对对象的访问,这个时候我们完全可以为访问添加访问日志等。在不采用其他框架情况下,我们要这个类型的对象都为代理对象的话,可以通过工厂或者是单例模式来实现,这样可以把日志代码隐藏,保持对象的简洁。

    




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值