黑马程序员-代理

来源:互联网 发布:笔记本电脑如何优化 编辑:程序博客网 时间:2024/06/10 20:29

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ---------------------

代理:

 

动态代理类:

JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理。

JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。

CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。

 

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

现在想要创建一个Proxy,根据API提供的方法,

Class clazz=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);

首先需要明确一个接口,就是要代理的接口,然后第一个参数是一个类加载器,这个类加载器一般跟这个接口的类加载器相同。

现在我想打印出这个代理类的构造函数,以及这些构造函数的参数类型

import java.lang.reflect.Constructor;import java.lang.reflect.Proxy;import java.util.Collection;public class ProxyCollection {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubClass clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);// System.out.println(clazz.getName());// 现在想打印出所有的构造函数,并且如果是有参构造函数,就让他带上参数类型StringBuilder sb = new StringBuilder();Constructor[] constructors = clazz.getConstructors();for (Constructor constructor : constructors) {sb.append(constructor.getName());sb.append('(');Class[] clazzs = constructor.getParameterTypes();for (Class clazz1 : clazzs) {sb.append(clazz1.getName()).append(',');}if (clazzs != null && clazzs.length != 0) {sb.deleteCharAt(sb.length() - 1);}sb.append(')');System.out.println(sb);}}}

打印结果:

 

可是我有个问题,这样做明显更简单,而且可以实现相同效果:

public static void main(String[] args) {// TODO Auto-generated method stubClass clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);// System.out.println(clazz.getName());// 现在想打印出所有的构造函数,并且如果是有参构造函数,就让他带上参数类型StringBuilder sb = new StringBuilder();Constructor[] constructors = clazz.getConstructors();for (Constructor constructor : constructors) {sb.append(constructor);System.out.println(sb);}}

打印结果:

 

现在把构造函数换成普通方法试试:

public static void main(String[] args) {// TODO Auto-generated method stubClass clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);// System.out.println(clazz.getName());// 现在想打印出所有的构造函数,并且如果是有参构造函数,就让他带上参数类型StringBuilder sb = new StringBuilder();Method[] methods = clazz.getMethods();for (Method method : methods) {sb.append(method);sb.append("\n");}System.out.println(sb);}

打印结果:

 

再用老师的方法试试:

public static void main(String[] args) {// TODO Auto-generated method stubClass clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);// System.out.println(clazz.getName());// 现在想打印出所有的构造函数,并且如果是有参构造函数,就让他带上参数类型StringBuilder sb = new StringBuilder();Method[] methods = clazz.getMethods();for (Method method : methods) {// sb.append(method);sb.append(method.getName());sb.append('(');Class[] clazzs = method.getParameterTypes();for (Class clazz1 : clazzs) {sb.append(clazz1.getName()).append(',');}if (clazzs != null && clazzs.length != 0) {sb.deleteCharAt(sb.length() - 1);}sb.append(')');sb.append("\n");}System.out.println(sb);}

打印结果:

 

利用动态代理创建对象:

public class ProxyCollection {/** * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubClass clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);Constructor constructor = clazz.getConstructor(InvocationHandler.class);class MyInvocationHandle implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubreturn null;}}Collection collection = (Collection) constructor.newInstance(new MyInvocationHandle());System.out.println(collection);}}

但是用这种方式创建的时候,感觉必须先提前知道构造函数的类型和个数。

代理详见:http://blog.csdn.net/caoyinghui1986/article/details/2450221  感觉讲的还不错,可以看看。


下面以Collection接口为列来进一步加强对动态代理的了解。

 

调用coll.clear()方法时,正常运行,调用add()方法时,报错,通过以上就可了解它为什么会报错,invoke()方法的返回值为null,它的返回值就是调用add()方法的返回值,add()方法本来是要返回boolean型数据的,但是现在返回的却是null,显然,null是不能转换为boolean型的。

现在我们写一种较为简单的方法:

Collection coll = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),new Class[] { Collection.class }, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method,Object[] args) throws Throwable {// TODO Auto-generated method stubreturn null;}});

继续修改代码:

 

一般代理类在代理时,需要执行一些额外的方法,一般把这些方法定义成一个对象,而且,要被代理的类也不能用硬编码写死。

import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.Collection;public class ProxyCollection1 {/** * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubfinal ArrayList list = new ArrayList();Advice advice = new Actrual();Object coll = proxy(list, advice);coll.toString();}public static Object proxy(final Object target, final Advice advice) {Object coll = (Object) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method,Object[] args) throws Throwable {// TODO Auto-generated method stub// 这儿一般要做一些工作,对于这些要做的事情,我们一般把这些方法封装到一个类中,但是,我们怎么知道这个类// 中又哪儿方法,不知道有如何调用?所以我们要定义一个接口,这个类必须实现该接口advice.beforeRun();Object obj = method.invoke(target, args);// 这儿也要做一些工作advice.afterRun();return obj;}});return coll;}}

Advice接口

public interface Advice {void beforeRun();void afterRun();}

Actrual

public class Actrual implements Advice {@Overridepublic void beforeRun() {// TODO Auto-generated method stubSystem.out.println("方法执行之前");}@Overridepublic void afterRun() {// TODO Auto-generated method stubSystem.out.println("方法执行之后");}}

实现AOP(面向方面编程)功能的封装与配置

原理:

哎,困难查重,终于做完,只是大概了解,后面还的好好看看,以下是代码:

BeanFactory

package Spring;import java.io.IOException;import java.io.InputStream;import java.util.Properties;public class BeanFactory {InputStream ins;Properties prop = new Properties();public BeanFactory(InputStream ins) {this.ins = ins;}public Object getBean(String str) {Object obj = null;try {prop.load(ins);String str1 = prop.getProperty(str);obj = Class.forName(str1).newInstance();if (obj instanceof ProxyBeanFactory) {Advice advice = (Advice) Class.forName(prop.getProperty("xxx" + ".advice")).newInstance();Object target = Class.forName(prop.getProperty("xxx" + ".target")).newInstance();Object proxy = ((ProxyBeanFactory) obj).getProxy(target, advice);return proxy;}} catch (Exception e) {}return obj;}}

ProxyBeanFactory

package Spring;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyBeanFactory {public Object getProxy(final Object target, final Advice advice) {Object coll = (Object) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method,Object[] args) throws Throwable {// TODO Auto-generated method stub// 这儿一般要做一些工作,对于这些要做的事情,我们一般把这些方法封装到一个类中,但是,我们怎么知道这个类// 中又哪儿方法,不知道有如何调用?所以我们要定义一个接口,这个类必须实现该接口advice.beforeRun();Object obj = method.invoke(target, args);// 这儿也要做一些工作advice.afterRun();return obj;}});return coll;}}

Config.properties配置文件

xxx=java.util.ArrayList#xxx=Spring.ProxyBeanFactoryxxx.advice=Spring.Actrualxxx.target=java.util.ArrayList

Advice

package Spring;public interface Advice {void beforeRun();void afterRun();}

Actrual


 

package Spring;public class Actrual implements Advice {@Overridepublic void beforeRun() {// TODO Auto-generated method stubSystem.out.println("方法执行之前");}@Overridepublic void afterRun() {// TODO Auto-generated method stubSystem.out.println("方法执行之后");}}
AppFrameworkTest

package Spring;import java.io.FileInputStream;import java.io.InputStream;public class AppFramworkTest {/** * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubInputStream ins = new FileInputStream("config.properties");BeanFactory bf = new BeanFactory(ins);Object obj = bf.getBean("xxx");System.out.println(obj.getClass().getName());}}



---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ---------------------

0 0