黑马程序员 Java学习总结之Java反射机制、代理以及AOP概念

------- android培训java培训、期待与您交流! ----------

之所以把Java反射机制、代理类以及AOP概念放在一起,在学习它们的过程中感觉上它们背后的思想对于使用Java构建框架以及理解别的Java框架很有帮助。事实上我在学习一项新的知识的时候总是倾向于先通览这个知识的方方面面,知道这项知识的总体框架如何,然后以联系的观点审视这个知识的各个部分,之后将它和其它知识互通起来,最后再重新从这个知识最基础的地方开始,以一种“会当凌绝顶,一览众山小”的高度温习这个知识。

本文先说说Java的反射机制,之后讲解一下Java的代理类和AOP概念,最后将一个虽然简陋但是完整的AOP框架的例子展示如何使用它们构建一个自己的小框架。当然这个框架只是用来演示功能没什么实际价值。

Java的反射就是把Java类中的各种成分映射成相应的Java类,包括类本身。我们知道一个Java对象的创建依赖于相应的类,而类加载到内存中是以字节码的形式存在的,在Java中表示一个类在内存中的字节码用一个Class类的实例来表示。并且一个类中的各个组成部分:成员变量、成员方法、构造函数,甚至于包都可以分别用一个Java类的实例来表示,例如Field、Method、Constructor、Package。然后使用这些类提供的方法,就可以在得不到这个类具体内容是什么的时候,获得相应部分的具体内容。但是首先我们需要获得这个类在内存中的字节码对应的实例对象,才可以通过Class类中的方法获得这个类具体的内容是什么。

获得字节码对应的Class类实例对象的方法:

1.类名.Class;

2.对象.getClass();

3.Class.forName(“完整的类名”),强调一下一个完整的类名包括:包名和类名。

有了字节码对象就可以通过Class类提供的各种方法获得相应类的各个组成部分:

得到某个类的所有构造方法

<span style="white-space:pre">	</span>Constructor [] constructors = Class.forName("some class's whole name").getConstructors();
也可以获得某一个构造方法,不过你得知道要传入这个构造方法的参数的类型:

<span style="white-space:pre">	</span>Constructor constructor = Class.forName("Java.lang.String").getConstructor(StringBuffer.class);
当然有了构造方法你总得想new一个对象,那么可以使用Constructor类提供的newInstance()方法。

<span style="white-space:pre">	</span>String str = (String)aConstructor.newInstance(new StringBuffer("abc"));
当然有了一个类的字节码对象是可以直接通过它来生成这个类的实例对象的:

String str = (String)Class.forName("java.lang.String").newInstance();

以此类推当然还可以获得一个类的成员方法,成员变量等等,其方法与上面类似,这里就不再赘述了。

不过还是要来提提“暴力反射”的。我们知道任何在类中处于成员位置的部分都可以被Private关键字修饰从而对外隐藏,获得这些被Private关键字所修饰的类的成员手法上有些不同,不过用一个例子就很好理解了:

<span style="white-space:pre">	</span>Field aPrivateField = anObj.getClass().getDeclaredField("thePrivateFieldName");
<span style="white-space:pre">	</span>aPrivateField.setAccessible(true);
上面就是所谓“暴力反射”了。没什么难的吧!对于其它的部分,也就是这个模式,所以也不再废话了。

下面说说Java代理类以及AOP概念。生活中的代理:武汉人从武汉的代理商手中买联想电脑和直接跑到北京传智播客旁边来找联想总部买电脑,你觉得最终的主体业务目标有什么区别吗?基本上一样吧,都解决了核心问题,但是,一点区别都没有吗?从代理商那里买真的一点好处都没有吗?程序中的代理:要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等,你准备如何做?编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上额外的系统功能的代码。如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。

简言之,代理就是在不修改一个类内容的情况下给这个类增加一些额外的功能。代理类就是实现这个需求的那个类。

所谓的AOP即是Aspect Oriented Program,面向方面编程。其实很简单,上面说有时需要在不修改一个类的情况下为这个类增加一些功能,那么有时候需要为多个类增加相同的增强功能,但前提还是不修改这些类。这个就是AOP所要解决的问题了。

那么具体怎么实现呢。在Java中可以使用动态代理技术来实现。需要注意的是在Java中想要通过动态代理来获得某个类的代理类,这个类必须实现一个或多个接口。下面使用两个例子来讲解如何使用Java动态代理来获得某个类的代理类。

使用Proxy.getProxyClass()获得代理类的方法:

Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
		class MyInvocationHander1 implements InvocationHandler{

			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				return null;
			}
		
		}
		Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());

使用Proxy.newInstance()直接获得某个类的代理类:

Object proxy3 = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandlerImpl())

InvocationHandlerImpl()是InvocationHandler()的实现类,实现类要覆写InvocationHandler()里的invoke()方法,注意invoke()传入的参数:生成的代理的实例对象、这个对象调用代理类的方法、这个方法所要的参数。通过在invoke()方法里调用某个需要增强功能的方法然后在这个被调用方法周围编写需要增强的功能,这样就实现了代理的目的。

下面给出一个综合的示例来展示代理以及Java反射机制的综合运用:

这个示例是一个小的AOP框架,目的是根据配置文件生成一个类的代理类。配置文件如下:

#xxx=java.util.ArrayList
xxx=cn.itcast.day3.aopframework.ProxyFactoryBean
xxx.advice=cn.itcast.day3.MyAdvice
xxx.target=java.util.ArrayList
这里“#”表示注释,当xxx=java.util.ArrayList时,直接返回ArrayList的对象,如果第二行有效,则根据生成target所配置的类的代理类对象。

下面是实际代码:

public class AopFrameworkTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
		Object bean = new BeanFactory(ips).getBean("xxx");
		System.out.println(bean.getClass().getName());
		((Collection)bean).clear();
	}

}
public class BeanFactory {
	Properties props = new Properties();
	public BeanFactory(InputStream ips){
		try {
			props.load(ips);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public Object getBean(String name){
		String className = props.getProperty(name);
		Object bean = null;
		try {
			Class clazz = Class.forName(className);
			bean = clazz.newInstance();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		if(bean instanceof ProxyFactoryBean){
			Object proxy = null;
			ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
			try {
				Advice advice = (Advice)Class.forName(props.getProperty(name + ".advice")).newInstance();
				Object target = Class.forName(props.getProperty(name + ".target")).newInstance();
				proxyFactoryBean.setAdvice(advice);
				proxyFactoryBean.setTarget(target);
				proxy = proxyFactoryBean.getProxy();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return proxy;
		}
		return bean;
	}
}
<pre name="code" class="java">public class ProxyFactoryBean {

	private Advice advice;
	private Object target;
	
	public Advice getAdvice() {
		return advice;
	}

	public void setAdvice(Advice advice) {
		this.advice = advice;
	}

	public Object getTarget() {
		return target;
	}

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

	public Object getProxy() {
		// TODO Auto-generated method stub
		Object proxy3 = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				/*new Class[]{Collection.class},*/
				target.getClass().getInterfaces(),
				new InvocationHandler(){
				
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						advice.beforeMethod(method);
						Object retVal = method.invoke(target, args);
						advice.afterMethod(method);
						return retVal;						
						
					}
				}
				);
		return proxy3;
	}

}


 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值