java-动态代理-简单实现AOP

       学过spring的人应该都知道,spring里有一项很牛逼的技能就是AOP,面相切面编程,用的原理就是java的动态代理机制。spring的aop例子可以参照下面博客,说的很清楚,我就不写了,今天只来实现一下java的动态代理。

        AOP小例子1        AOP小例子2

        还是以昨天的博客,上网代理为例子。首先是上网接口:

/**
 * IsubJect: 上网接口(被代理类的接口)
 * 
 * @author xuejupo [email protected]
 * 
 *         create in 2015-12-23 下午1:31:13
 * 
 */
interface IsubJect {
	public void request(String url);
}

 上网类:

/**
 * MySubject: 具体上网类(被代理类)
 * 
 * @author xuejupo [email protected]
 * 
 *         create in 2015-12-23 下午1:33:21
 * 
 */
public class MySubject implements IsubJect {
	@Override
	public void request(String url) {
		// TODO Auto-generated method stub
		System.out.println("您打开了网址:" + url);
	}
}

 好了,上网类就算实现了,并且已经发布到现场版本了,不能轻易修改了。那么我们想对上网操作做修改怎么办?  使用动态代理:

        首先定义几个接口,就像spring中的MyBeforeAdvice等接口一样:

/**  
* Before: 动态代理中,在执行方法前做的事,相当于aop中的MyBeforeAdvice接口
* @author xuejupo  [email protected] 
* create in 2015-12-23 下午2:34:53  
*    
*/
interface Before{
	void beforTheMonth();
}

/**  
* after:动态代理中,在执行方法后做的事,相当于aop中的MyAfterAdvice接口
* @author xuejupo  [email protected] 
* create in 2015-12-23 下午2:36:51  
*    
*/
interface After{
	void afterTheMonth();
}

/**  
* interTheMethod: 动态代理中,在执行方法的时候,转执行该方法,相当于aop中的MyMethodInterceptor接口
* @author xuejupo  [email protected] 
* create in 2015-12-23 下午2:38:27  
*    
*/
interface InterTheMethod{
	Object theOtherMethod(Object objcet,Method method, Object[] args);
}

     好了,定义好接口以后,就应该实现这些接口,扩充我们的业务:

/**  
* BeforClass: 动态代理中前置方法
* @author xuejupo  [email protected] 
* create in 2015-12-24 下午8:09:40  
*    
*/
class BeforClass implements Before {

	@Override
	public void beforTheMonth() {
		// TODO Auto-generated method stub
		System.out.println("动态代理before方法:做好上网前准备-----");
	}
}

/**  
* AfterClass:动态代理中后置方法
* @author xuejupo  [email protected] 
* create in 2015-12-24 下午8:10:04  
*    
*/
class AfterClass implements After {
	@Override
	public void afterTheMonth() {
		// TODO Auto-generated method stub
		System.out.println("动态代理after方法:上网完成记得结账-----");
	}
}

/**  
* innerClass:动态代理中插入方法
* @author xuejupo  [email protected] 
* create in 2015-12-24 下午8:10:12  
*    
*/
class innerClass implements InterTheMethod {

	@Override
	public Object theOtherMethod(Object object,Method method, Object[] args) {
		// TODO Auto-generated method stub
		System.out.println("动态代理inner方法:执行该方法就不一定执行原来的方法了,在这个方法里判断:");
		if(args[0].equals("youku.com")){
			System.out.println("幸好我用代理,发现你小子看优酷了!禁止访问!!!");
		}else{
			try {
				System.out.println("原来不是看优酷呀,放过你了,继续看吧:");
				method.invoke(object, args);
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

}

 既然是模拟aop,aop里面是怎么做的?   在配置文件里面配相应的参数,使得在执行主要方法之前或者之后,能够执行我们的逻辑方法。应该有个类实现模拟aop中读取xml参数的行为,太麻烦了。。   做一个bean类,分别用几个get方法模拟一下读取xml文件中读取相应类的方法:

package InvolvedMode.proxy.dynamicProxy;

import java.util.ArrayList;
import java.util.List;

/**
 * DynamicXmlBean :
 * 
 * @author xuejupo [email protected]
 * 
 *         create in 2015-12-23 下午1:44:44
 */

public class DynamicXmlBean {
	/**
	 * @Fields beanMap : 模拟aop中xml配置中的bean配置
	 */
	private static List<Class<?>> beanList = new ArrayList<Class<?>>();
	//初始化
	static{
		try{
			beanList.add(Class.forName("InvolvedMode.proxy.dynamicProxy.BeforClass"));
			beanList.add(Class.forName("InvolvedMode.proxy.dynamicProxy.AfterClass"));
			beanList.add(Class.forName("InvolvedMode.proxy.dynamicProxy.innerClass"));
		}catch(Exception e){
			e.fillInStackTrace();
		}
	}
	/**  
	* getBeforeClass: 获取before方法(在真正方法前应该执行的类)
	* @param name
	* @return 
	* Class<?>  返回类型   
	*/
	public static Class<?> getBeforeClass(){
		for(Class<?> c:beanList){
			if(Before.class.isAssignableFrom(c)){
				return c;
			}
		}
		return null;
	}
	
	/**  
	* getAfterClass: 获取after方法(在真正方法执行之后执行的方法)
	* @return 
	* Class<?>  返回类型   
	*/
	public static Class<?> getAfterClass(){
		for(Class<?> c:beanList){
			if(After.class.isAssignableFrom(c)){
				return c;
			}
		}
		return null;
	}
	
	/**  
	* getInnerClass: 获取inner方法(在真正方法执行时,转而执行的方法)
	* @return 
	* Class<?>  返回类型   
	*/
	public static Class<?> getInnerClass(){
		for(Class<?> c:beanList){
			if(InterTheMethod.class.isAssignableFrom(c)){
				return c;
			}
		}
		return null;
	}
}

 真正的动态代理类,实现java自带的InvocationHandler接口:

package InvolvedMode.proxy.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Dproxy:动态代理类
 * 
 * @author xuejupo [email protected] create in 2015-12-23 下午2:09:16
 * 
 */
class Dproxy implements InvocationHandler {
	// 要代理的对象
	private Object obj = null;

	// 我要代理谁
	public Dproxy(Object _obj) {
		this.obj = _obj;
	}

	// 调用被代理的方法
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("---------------进入代理类了:");
		Object result = null;
		this.beforeMethod();
		// 其次,查找DynamicXmlBean中的inner类,如果存在,就不执行该方法
		Class<?> inner = DynamicXmlBean.getInnerClass();
		if (inner == null) {
			result = method.invoke(this.obj, args);
		} else {
			result = this.inner(inner, method, args);
		}
		this.afterMethod();
		return result;
	}

	/**
	 * beforeMethod: 代码执行前的方法 void 返回类型
	 */
	private void beforeMethod() {
		// 首先,查找DynamicXmlBean中的before类(模拟aop中查找xml中的MyBeforeAdvice接口)
		Class<?> before = DynamicXmlBean.getBeforeClass();
		if (before != null) {
			this.before(before);
		}
	}

	/**  
	* afterMethod:  代码执行完成后的方法(如果结果不依赖此,可以改成线程的方式)
	* void  返回类型   
	*/
	private void afterMethod() {
		// 方法执行完成后,查找DynamicXmlBean中的after类(模拟aop中查找xml中的MyAfterAdvice接口)
		Class<?> after = DynamicXmlBean.getAfterClass();
		if (after != null) {
			this.after(after);
		}
	}

	/**
	 * before: 代码执行前方法
	 * 
	 * @param c
	 *            void 返回类型
	 */
	private void before(Class<?> c) {
		try {
			Before b = (Before) c.newInstance();
			b.beforTheMonth();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * inner: 代码执行转换方法
	 * 
	 * @param c
	 *            void 返回类型
	 */
	private Object inner(Class<?> c, Method method, Object[] args) {
		Object result = null;
		try {
			InterTheMethod b = (InterTheMethod) c.newInstance();
			result = b.theOtherMethod(this.obj, method, args);
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * after: 代码执行后的方法
	 * 
	 * @param c
	 *            void 返回类型
	 */
	private void after(Class<?> c) {
		try {
			After b = (After)c.newInstance();
			b.afterTheMonth();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 可以看到,动态代理里面没有针对特定产品的代码,即动态代理是对产品解耦的。无论你需要多少代理,一个动态代理就够了,你要做的就是多配置几个xml参数和多实现几个Before或者After接口,简单粗暴。

    测试类:

package InvolvedMode.proxy.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * AOP例子:http://honda418.iteye.com/blog/339468
 * http://www.blogjava.net/javadragon/archive/2006/12/03/85115.html 
 * DynamicProxyTest: 动态代理测试类
 * 
 * @author xuejupo [email protected]
 * 
 *         create in 2015-12-23 上午10:25:03
 */

public class DynamicProxyTest {
	public static void main(String[] args) {
		IsubJect sub = new MySubject();
		InvocationHandler handler = new Dproxy(sub);
		// 创建代理对象
		IsubJect ob = (IsubJect) Proxy.newProxyInstance(
				sub.getClass().getClassLoader(),
				sub.getClass().getInterfaces(), handler);
		ob.request("youku.com");
                ob.request("youku.com.cn");
	}
}

 结果:

---------------进入代理类了:
动态代理before方法:做好上网前准备-----
动态代理inner方法:执行该方法就不一定执行原来的方法了,在这个方法里判断:
幸好我用代理,发现你小子看优酷了!禁止访问!!!
动态代理after方法:上网完成记得结账-----
---------------进入代理类了:
动态代理before方法:做好上网前准备-----
动态代理inner方法:执行该方法就不一定执行原来的方法了,在这个方法里判断:
原来不是看优酷呀,放过你了,继续看吧:
您打开了网址:youku.com.cn
动态代理after方法:上网完成记得结账-----

猜你喜欢

转载自709002341.iteye.com/blog/2266317