码迷,mamicode.com
首页 > 编程语言 > 详细

跟我学Java反射——四步曲

时间:2015-05-31 21:42:44      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:aop   动态代理   反射   


    前面的三篇文章我们将反射的基础知识和通过反射来得到运行类的结构,比如、属性、方法、父类、接口、注解等一些内容,并对如何通过反射来调用运行类的指定属性和方法,这篇文章我们学习一个运行反射的典型,动态代理与AOP的结合。 

 

AOP动态代理

 

    先来介绍一种情况,代码段123都含有相同的代码段,以前的方法通过复杂粘贴重复的代码段来完成,如图: 

技术分享

 

     上面描述的这种情况,必然是可以进行改进的,我们将重复的代码抽离出来,让代码段123通过方法调用的形式来调用抽离出来的那段重复的代码段,这样相对于上面的图来说,是将代码段123和重复的代码段分了开了,但是代码段123又和抽离出来的那段代码耦合了,如下图:

技术分享

 

    比较理想的效果就是:代码段123即可用执行方法A,又不用再程序中以方法调用或者说硬编码的方式调用,而AOP动态代理就可以很好地解决这个问题。

 

    关于AOP动态代理的实现常用的有利用jdk的反射还有CGLib,它们的区别是前者不可以代理没有接口的类而CGlib可以,具体的我们不再多说,因为这篇文章主要是为了应用一下前面三篇文章里说的反射,所有我们的动态代理用jdk本身自带的反射来实现。所有接下来我们就用jdk的动态代理来解决这个问题。

 

 

具体实现

 

 

 

技术分享

 

 

    首先是被代理接口Hello:

 

<span style="font-family:KaiTi_GB2312;">package com.tgb.state;

/**
 * 
 * @author kang
 *
 */
public interface Hello {
	
	public void say(String name);

}
</span>


    被代理接口Hello的实现类HelloImpl:

 

<span style="font-family:KaiTi_GB2312;">package com.tgb.state;


public class HelloImpl implements Hello {

	@Override
	public void say(String name) {
		System.out.println(this.getClass()+"  Hello!"+name);
	}

}
</span>



    抽离出来的通用代码类ServiceBean:

<span style="font-family:KaiTi_GB2312;">package com.tgb.dynamic.jdk;

import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * 服务bean,是作为aop中需要复用的功能
 * @author kang
 *
 */
public class ServiceBean {

	// 盛放代理对象方法之前的对象
	HashMap<String, Object> beforeBeans = new HashMap<String, Object>();
	// 盛放代理对象方法之后的对象
	HashMap<String, Object> afterBeans = new HashMap<String, Object>();

	// 盛放代理对象方法之前的对象的方法
	HashMap<String, String> beforeMethods = new HashMap<String, String>();
	// 盛放代理对象方法之后的对象的方法
	HashMap<String, String> afterMethods = new HashMap<String, String>();

	public  void before() throws Exception{
		for (HashMap.Entry<String, Object> entry : beforeBeans.entrySet()) {
			String beanKey = entry.getKey();
			Object beforeBean = entry.getValue();
			
			String beforeMethodValue = beforeMethods.get(beanKey);
//			System.out.println("beforeMethodValue:"+beforeMethodValue);
			
			//利用反射拿到类的要执行的方法
			Method beforeMethod = beforeBean.getClass().getMethod(beforeMethodValue);
//			System.out.println("beforeMethod:"+beforeMethod);
			
			//利用反射执行运行类需要执行的方法
			beforeMethod.invoke(beforeBean);
		}
//		System.out.println(this.getClass()+"Before");
	}

	public void after() throws Exception {

		for (HashMap.Entry<String, Object> entry : afterBeans.entrySet()) {
			String beanKey=entry.getKey();
			Object afterBean=entry.getValue();
			
			String afterMethodValue=afterMethods.get(beanKey);
//			System.out.println("afterMethodValue:"+afterMethodValue);
			
			//利用反射拿到类的要执行的方法
			Method afterMethod = afterBean.getClass().getMethod(afterMethodValue);
//			System.out.println("afterMethod:"+afterMethod);

			//利用反射执行运行类需要执行的方法
			afterMethod.invoke(afterBean);
			
		}
//		System.out.println(this.getClass()+"After");
	}
	
	

	public HashMap<String, Object> getBeforeBeans() {
		return beforeBeans;
	}

	public void setBeforeBeans(HashMap<String, Object> beforeBeans) {
		this.beforeBeans = beforeBeans;
	}

	public HashMap<String, Object> getAfterBeans() {
		return afterBeans;
	}

	public void setAfterBeans(HashMap<String, Object> afterBeans) {
		this.afterBeans = afterBeans;
	}

	public HashMap<String, String> getBeforeMethods() {
		return beforeMethods;
	}

	public void setBeforeMethods(HashMap<String, String> beforeMethods) {
		this.beforeMethods = beforeMethods;
	}

	public HashMap<String, String> getAfterMethods() {
		return afterMethods;
	}

	public void setAfterMethods(HashMap<String, String> afterMethods) {
		this.afterMethods = afterMethods;
	}


}
</span>


        处理类MyInvokationHandler:


<span style="font-family:KaiTi_GB2312;">package com.tgb.dynamic.jdk;

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

/**
 * 处理类,用来装载复用的代码类
 * @author kang
 *
 */
public class MyInvokationHandler implements InvocationHandler{

	private ServiceBean serviceBean;
	
	private Object target;

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

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

	public ServiceBean getServiceBean() {
		return serviceBean;
	}

	public void setServiceBean(ServiceBean serviceBean) {
		this.serviceBean = serviceBean;
	}


	
	
}
</span>

    动态生成代理对象的代理类MyProxyFactory


<span style="font-family:KaiTi_GB2312;">package com.tgb.dynamic.jdk;

import java.lang.reflect.Proxy;


public class MyProxyFactory {
		/**
		 * 生成代理对象
		 * @return
		 */
		@SuppressWarnings("unchecked")
		public static <T> T getProxy(Object target,MyInvokationHandler handler ){
			//为MyInvokationHandler设置target对象
			handler.setTarget(target);
			// 创建、并返回一个动态代理对象
			return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
		}
}
</span>

 

    到这里aop动态代理的整体类就已经有了,细心的同学会发现,ServiceBean服务类有点复杂,是因为我们这里将服务类做了抽象,让服务类可以在使用时也利用反射来动态装载需要复用的功能类,里面的反射代码都是我们在前三篇文章中学到的。

 

    下面我们来看下,需要动态装载的复用的功能类HiImpl


<span style="font-family:KaiTi_GB2312;">package com.tgb.state;

public class HiManage{

	public void hi() {
		System.out.println(this.getClass()+"的Before方法"+"hi方法");
	}

	public void bye() {
		System.out.println(this.getClass()+"的after方法"+"bye方法");
		
	}
	
}
</span>

 

    接下来看下我们的客户端代码:


<span style="font-family:KaiTi_GB2312;">package com.tgb.dynamic.jdk;

import java.util.HashMap;

import com.sun.org.apache.bcel.internal.generic.NEW;
import com.tgb.state.HiManage;

public class Client4 {

	public static void main(String[] args) {
	//---------------  装载可复用的功能类 --------------------------
	HashMap<String, Object> beforeBeans = new HashMap<String, Object>();
	HashMap<String, Object> afterBeans = new HashMap<String, Object>();
	HashMap<String, String> beforeMethods = new HashMap<String, String>();
	HashMap<String, String> afterMethods = new HashMap<String, String>();
	beforeBeans.put("HiManage", new HiImpl1());
	afterBeans.put("HiManage", new HiImpl1());
	beforeMethods.put("HiManage", "hi");
	afterMethods.put("HiManage", "bye");
	ServiceBean serviceBean = new ServiceBean();
	serviceBean.setBeforeBeans(beforeBeans);
	serviceBean.setAfterBeans(afterBeans);
	serviceBean.setBeforeMethods(beforeMethods);
	serviceBean.setAfterMethods(afterMethods);
	//------------------装载可复用的功能类-----------------------
	
	//将装载完成后的可复用的功能类,设置到处理类中
	MyInvokationHandler handler = new MyInvokationHandler();
	handler.setServiceBean(serviceBean);
	
	//生成代理对象
	Hello helloProxy=MyProxyFactory.getProxy(new HelloImpl(),handler);

	helloProxy.say("zhangsan");

	}

}
</span>

运行结果:


        class com.tgb.state.HiManage的Before方法hi方法

        class com.tgb.state.HelloImpl  Hello!zhangsan

        class com.tgb.state.HiManage的after方法bye方法

 

 

    到这里一个利用jdk反射实现的aop动态代理就完成了,上图3中左边的HelloHelloImpl是被代理类,最右边的ServiceBean是要被复用的抽象功能类,只是我们把这个抽象功能类又做了一层抽象和封装,利用反射让这个ServiceBean可以动态加载具体要被复用的功能类例如HiManage类。在上图中的线1、和线2都是在客户端调用时才会动态生成Hello的代理类,并将复用的功能类HiManage动态装载,共同实现了我们的AOP动态代理。


 

后记

 

    通过前前后后这一共四篇文章,我们对反射的知识通过具体demo代码进行了学习,包括class对象创建、class对象实例生成,以及class类的具体结构如构造函数、属性、方法、注解、父类、实现接口等这些知识,最后又介绍了反射的一个典型应用aop动态代理,关于反射就先介绍到这来。


跟我学Java反射——四步曲

标签:aop   动态代理   反射   

原文地址:http://blog.csdn.net/zwk626542417/article/details/46291855

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!