JDK 动态代理

        代理模式,现在基本每个框架都在用,所以弄懂动态代理很有必要,我们先看一个代理模式图


根据上面的图我们来实现JDK的动态代理:

1、创建Subject接口;

2、创建实现Subject的实现子类RealSubject;

3、创建实现InvocationHandler的实现子类;

4、创建RealSubject的代理类;

5、通过代理类去执行实现接口的子类的方法;


一、创建Subject接口

public interface Subject {

	public void request();
	
}

二、创建实现Subject的实现子类RealSubject

public class RealSubject implements Subject {
	@Override
	public void request() {
		System.out.println("the request method of RealSubject");
	}
}

三、创建实现InvocationHandler的实现子类

public class CustomInvocationHandler implements InvocationHandler {

	// 目标对象
	private Object target;

	public CustomInvocationHandler() {
	}

	public CustomInvocationHandler(Object target) {
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		before();
		Object obj = method.invoke(target, args);
		after();	
		return obj;
	}

	/**
	 * 前置通知
	 */
	private void before() {
		System.out.println("-- 插入前置通知代码 --");
	}

	/**
	 * 后置通知
	 */
	private void after() {
		System.out.println("-- 插入后置通知代码 --");
	}
}

四、创建代理并且通过代理类的调用去执行实际实现接口子类的方法

public class Test {

	public static void main(String[] args) throws Exception {
		// 通过反射获取被代理类
		Class<?> targetClazz = Class.forName("com.jjx.proxy.RealSubject");
		
		// 生成代理对象
		Subject subjectProxy = (Subject) Proxy.newProxyInstance(
				Test.class.getClassLoader(), 					// 类加载器
				targetClazz.getInterfaces(), 					// 代理类所需要实现的接口(即实现类所实现的所有接口,这是个接口数组)
				new CustomInvocationHandler(targetClazz.newInstance()));	// 调用处理器去调用接口实现类的方法
		
		// 通过代理去执行接口实现类的方法
		subjectProxy.request();
	}

}

        上面就基本上完成了动态代理,但是我们在SpringMVC中都知道类中的方法还有注解(Annotation)的,这里我们就上级一下,来实现有注解的方法,这里就简单的实现一下类似Advice的注解,注解代码如下:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyTransaction {

	public AdviceType value();
}

        这里有一个AdviceType是什么呢?这个是个自定义的枚举,用来枚举列出advice的前置通知、后置通知和环绕通知,下面是AdviceType枚举类的代码:

public enum AdviceType {

	BEFORE("before"), AFTER("after"), AROUND("around");
 
	private String name;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	private AdviceType(String name) {
		this.name = name;
	}
}

       现在也把接口改一下,改后的代码如下:

public interface Subject {
        // 在此方法执行之前,执行前置通知
	public void needBeforeAdvice();
	// 在此方法执行之后,执行后置通知
	public void needAfterAdvice();
	// 在此方法执行之前,执行前置通知;在此方法执行之后,执行后置通知
	public void needAllAdvice();
	// 此方法不执行任何通知
	public void noAdvice();
}

        实现接口的实现子类代码如下:

public class RealSubject implements Subject {

	@Override
	@MyTransaction(AdviceType.BEFORE)    // 在needBeforeAdvice方法执行之前执行前置通知
	public void needBeforeAdvice() {
		System.out.println("the mothed of needBeforeAdvice in the RealSubject class");
	}

	@Override
	@MyTransaction(AdviceType.AFTER)    // 在needAfterAdvice方法执行之后执行后置通知
	public void needAfterAdvice() {
		System.out.println("the mothed of needAfterAdvice in the RealSubject class");
	}

	@Override
	@MyTransaction(AdviceType.AROUND)    // 在needAllAdvice方法执行之前,执行前置通知,该方法之后执行后置通知
	public void needAllAdvice() {
		System.out.println("the mothed of needAllAdvice in the RealSubject class");
	}

	@Override
	public void noAdvice() {            // 该方法不做任何处理
		System.out.println("the mothed of noAdvice in the RealSubject class");
	}

}

      我们在来看看InvocationHandler实现子类是如何实现的,代码如下:

public class CustomInvocationHandler implements InvocationHandler {

	// 目标对象
	private Object target;

	public CustomInvocationHandler() {
	}

	public CustomInvocationHandler(Object target) {
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 获取被代理类的方法(method是接口中的方法,不是实现类的方法,所以要获取实现类中的实现方法)
		Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());
		// 获取注解对象
		MyTransaction annotation = targetMethod.getAnnotation(MyTransaction.class);

		Object obj; // 返回对象

		// 如果该方法存在MyTransaction注解
		if (annotation != null) {
			// 获取注解对象属性value的值,因为value值是一个AdviceType枚举类型,通过getName()方法可以获取枚举的值
			String value = annotation.value().getName();

			// 如果注解中的值为before,就执行before()方法
			if (AdviceType.BEFORE.getName().equals(value)) {
				before();
				// 执行相应的目标方法
				obj = method.invoke(target, args);
				return obj;
			}

			// 如果注解中的值为around,就在执行方法之前执行before()方法,在执行方法之后执行after()
			if (AdviceType.AROUND.getName().equals(value)) {
				before();
				// 执行相应的目标方法
				obj = method.invoke(target, args);
				after();
				return obj;
			}

			// 如果注解中的值为after,就执行after()方法
			if (AdviceType.AFTER.getName().equals(value)) {
				// 执行相应的目标方法
				obj = method.invoke(target, args);
				after();
				return obj;
			}
		} else {	// 如果该方法没有MyTransaction注解
			// 执行相应的目标方法
			obj = method.invoke(target, args);
			return obj;
		}
		return null;
	}

	/**
	 * 前置通知
	 */
	private void before() {
		System.out.println("-- 插入前置通知代码 --");
	}

	/**
	 * 后置通知
	 */
	private void after() {
		System.out.println("-- 插入后置通知代码 --");
	}
}

      通过代理去调用这些方法,代码如下:

public class Test {

	public static void main(String[] args) throws Exception {
		// 通过反射获取被代理类
		Class<?> targetClazz = Class.forName("com.jjx.proxy.RealSubject");
		
		// 生成代理对象
		Subject subjectProxy = (Subject) Proxy.newProxyInstance(
				Test.class.getClassLoader(), 								// 类加载器
				targetClazz.getInterfaces(), 								// 代理类所需要实现的接口(即实现类所实现的所有接口,这是个接口数组)
				new CustomInvocationHandler(targetClazz.newInstance()));	// 调用处理器去调用接口实现类的方法
		
		// 通过代理去执行接口实现类的方法
		subjectProxy.needBeforeAdvice();
		System.out.println("==========================");
		subjectProxy.needAllAdvice();
		System.out.println("==========================");
		subjectProxy.needAfterAdvice();
		System.out.println("==========================");
		subjectProxy.noAdvice();
	}

}

得到的结果如下:

-- 插入前置通知代码 --
the mothed of needBeforeAdvice in the RealSubject class
==========================
-- 插入前置通知代码 --
the mothed of needAllAdvice in the RealSubject class
-- 插入后置通知代码 --
==========================
the mothed of needAfterAdvice in the RealSubject class
-- 插入后置通知代码 --
==========================
the mothed of noAdvice in the RealSubject class
这就达到了我们想要的结果,当然我这里只是简单的一个实现,只是用于自己巩固一下知识,希望没有误导到别人。
阅读更多
个人分类: j2ee
想对作者说点什么? 我来说一句

JDK动态代理_JDK动态代理

2009年10月18日 32KB 下载

没有更多推荐了,返回首页

不良信息举报

JDK 动态代理

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭