反射和动态代理
2015-06-16 20:28
495 查看
什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
如果我们拿到一个类的类型信息,就可以利用反射获取其各种成员以及方法了.通过反射调用方法例子如下:
/[b]*********************java动态代理(JDK和cglib)*************************[/b]/
java动态代理主要涉及2个类:1.interface InvocationHandler;2.class Proxy .
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
静态代理:
通过这些代码可以发现,CountProxy 代理类只能为Count这一个接口服务,这样必然会产生过多的代理,对比下面的动态代理差别就一目了然了。
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
如果我们拿到一个类的类型信息,就可以利用反射获取其各种成员以及方法了.通过反射调用方法例子如下:
package com.reflection; import java.lang.reflect.Method; public class ReflectionAPI { public static void main(String[] args) throws Exception { Class<?>cla=Class.forName("java.lang.String"); /* public Method[] getMethods()返回某个类的所有公用(public)方法包括其继 承类的公用方法,当然也包括它所实现接口的方法。 public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法, 包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所 实现接口的方法。 */ //返回class对象所对应的类或接口中,所声明的所有方法的数组(包括私有方法) Method[] method=cla.getDeclaredMethods(); //遍历输出所有方法声明 for(Method m:method){ System.out.println(m); } } } package com.reflect.method; public class InvokeTest { public int add(int id,int age){ return age; } public String reflect(String name){ return "hello:"+name; } } package com.reflect.method; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { //不用反射情况下, InvokeTest it=new InvokeTest(); System.out.println(it.add(1, 10)); System.out.println(it.reflect("张三")); System.out.println("---下面是使用反射的例子-----"); //使用反射首先获取类名 /*三种方式得到Class对象: 1.调用对象的getClass方法,返回该对象的Class对象 例如:String str = "aa"; Class<?> classType1 = str.getClass(); getClass()方法定义在Object类中,不是静态方法,需要通过对象来调用, 并且它声明 为final,表明不能被子类所覆写。 (Object方法有哪些。clone()、equals()、finalize()、getClass()、 面试官问过我这个问题。偶然想起了记录下来。) 2.Class.forName(“类的名字”);有个受查异常 如:Class.forName("java.lang.String"); 3.Class c=类名.class 例如:String.class; */ Class<InvokeTest> cla=InvokeTest.class; /*这里有必要提一下就是Class下的newInstance()和new有什么区别?, 首先,newInstance( )是一个方法, * 而new是一个关键字,其次,Class下的newInstance()的使用有局限, * 因为它生成对象只能调用无参的构造函数, * 而使用new关键字生成对象没有这个限制。好,到此为止,我们总结如下: * Class.forName("")返回的是类 * Class.forName("").newInstance()返回的是object. */ //这里生成新的对象,用newInstance()方法。 Object invokeTest=cla.newInstance(); System.out.println(invokeTest instanceof InvokeTest); /*通过反射调用方法,首先需要获得与该方法相对应的Method对象。 * */ // 第一个参数是方法名,第二个参数是这个方法所需要的参数的Class对象的数组 Method method=cla.getMethod("add", new Class[]{int.class,int.class}); Method method2=cla.getMethod("reflect", new Class[]{String.class}); Object object=method.invoke(invokeTest, new Object[]{1,10}); System.out.println(object); Object object2= method2.invoke(invokeTest, new Object[]{"反射"}); System.out.println(object2); } } 控制台输出结果: 10 hello张三 ---下面是使用反射的例子----- true 10 hello反射
/[b]*********************java动态代理(JDK和cglib)*************************[/b]/
java动态代理主要涉及2个类:1.interface InvocationHandler;2.class Proxy .
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
静态代理:
package neusoft.proxy.dao; public interface Count { //查看账户的方法. public void queryCount(); //修改账户的方法. public void updateCount(); } package neusoft.proxy.impl; import neusoft.proxy.dao.Count; public class CountImpl implements Count{ @Override public void queryCount() { System.out.println("**查询账户的方法**"); } @Override public void updateCount() { System.out.println("**修改账户的方法**"); } } package neusoft.proxy.impl; import neusoft.proxy.dao.Count; //这是一个代理类(增强CountImpl实现类) public class CountProxy implements Count{ private CountImpl countImpl; //覆盖默认构造器 public CountProxy(CountImpl countImpl) { this.countImpl = countImpl; } @Override public void queryCount() { //在这些方法里面增加一些业务逻辑,增强CountImpl实现类。 System.out.println("**事务处理之前**"); // // 调用委托类的方法; countImpl.queryCount(); System.out.println("**事务处理之后**"); } @Override public void updateCount() { System.out.println("**事务处理之前**"); // // 调用委托类的方法; countImpl.updateCount(); System.out.println("**事务处理之后**"); } } package neusoft.proxy.test; import neusoft.proxy.impl.CountImpl; import neusoft.proxy.impl.CountProxy; public class CountTest { public static void main(String[] args) { CountImpl countImpl=new CountImpl(); CountProxy countProxy=new CountProxy(countImpl); countProxy.queryCount(); countProxy.updateCount(); }
通过这些代码可以发现,CountProxy 代理类只能为Count这一个接口服务,这样必然会产生过多的代理,对比下面的动态代理差别就一目了然了。
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class
package neusoft.proxy.dao; public interface MyProxy { public void add(); //我们再添加一个方法; public void delete(); } package neusoft.proxy.impl; import neusoft.proxy.dao.MyProxy; public class MyProxyImpl implements MyProxy{ @Override public void add() { System.out.println("-----add方法---------------"); } @Override public void delete() { System.out.println("-----delete方法--------"); } } package neusoft.proxy.impl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //这是一个代理类(增强MyProxyImpl实现类) public class MyDynamicProxy implements InvocationHandler{ private Object pro; public MyDynamicProxy(Object obj){ this.pro=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doBefore(method); System.out.println(proxy.getClass().getSimpleName()); Object result= method.invoke(pro, args); return result; } public static void doBefore(Method method){ System.out.println(method.getName()+"方法执行*****doBefore******"); } } package neusoft.proxy.test; import java.lang.reflect.Proxy; import neusoft.proxy.dao.MyProxy; import neusoft.proxy.impl.CountProxy; import neusoft.proxy.impl.MyDynamicProxy; import neusoft.proxy.impl.MyProxyImpl; public class MyDynamicProxyTest { public static void main(String[] args) { //得到MyProxy接口的一个实例对象. MyProxy impl=new MyProxyImpl(); /* * 在java中实现动态代理步骤: * 1,由前面的静态代理可知,有一个接口,一个接口的实现类,而这个实现类就是我们要代理的对象。 * 所谓代理就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。 * 2,我们要自己写一个在要代理类的方法执行时,能够做额外工作的类,而这个类必须继承InvocationHandler接口, * 为什么要继承它呢?因为代理类的实例在调用实现类的方法的时候,不会调真正的实现类的这个方法, * 而是转而调用这个类的invoke方法(继承时必须实现的方法),在这个方法中你可以调用真正的实现类的这个方法。 在要用代理类的实例去调用实现类的方法的时候,写出下面两段代码。 */ MyProxy proxy=(MyProxy)Proxy.newProxyInstance(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), new MyDynamicProxy(impl)); /* * 第一,根据impl.getClass().getClassLoader()这个要代理类的类加载器和 * impl.getClass().getInterfaces()要代理类所实现的所有的接口 impl.getClass().getInterfaces()=new Class[]{MyProxy.class}; * 作为参数调用Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces) * 的方法返回代理类的java.lang.Class对象,也就是得到了java动态生成的代理类$Proxy0的Class对象。 * 同时,java还让这个动态生成的$Proxy0类实现了要代理类的实现的所有接口,并继承了Proxy接口。 * 第二,实例化这个动态生成的$Proxy0类的一个实例,实例化代理类的构造函数为Proxy(InvocationHandler h), * 也就是说要实例化这个动态生成的$Proxy0类,必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类 * 方法执行前后做额外工作的类MyDynamicProxy。 * 这段代码Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),new MyDynamicProxy(impl)) * 得到的其实是一个类名叫$Proxy0 extends Proxy implements MyProxy的类。 * 第三,将这个$Proxy0类强制转型成MyProxy类型,调用add方法。 */ proxy.add(); proxy.delete(); } } 输出结果: add方法执行*****doBefore****** $Proxy0 -----add方法--------------- 接口加上delete方法后,输出结果: add方法执行*****doBefore****** $Proxy0 -----add方法--------------- delete方法执行*****doBefore****** $Proxy0 -----delete方法---- 可以看到我们自己加的代理业务逻辑执行了2遍。
相关文章推荐
- Loader异步加载ContentProvider
- 46Exchange 2010升级到Exchange 2013-移除总部CAS2010
- 当“逻辑”与“UE”冲突时
- 执行后台命令
- Hadoop中HDFS写入文件的原理剖析
- Log4J配置
- org.hibernate.MappingException: Unknown entity
- bzoj 2482: [Spoj1557] Can you answer these queries II
- Android学习【按钮颜色修改】
- 一int考虑什么类型的多少字节
- c++中class与struct的区别
- ajax+json+Struts2实现list传递实例讲解
- CSS border实现三角形
- 从java到安卓学习笔记--到15-06-16
- 7-4
- MySQL-5.6.13免安装版配置方法
- 剑指Offer--面试题18:数的子结构--Java实现
- js实现的省市县三级联动的最新源码
- Js节点属性与方法
- 利用referer防止盗链下载