黑马程序员——高新技术(三)
来源:互联网 发布:图片横向滚动js代码 编辑:程序博客网 时间:2024/05/20 13:06
---------------------- android培训 java培训 期待与您交流! ----------------------
1,代理
为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能。采用工厂模式和配置文件方式进行管理,不需要改客户端程序,比如你要给你的项目测试运行时间,在方法前后计算时间,这时改配置文件用的是代理,
最后觉得性能可以,可以卖给用户了,这时候要把计算时间的代码去掉,修改配置文件就可以了。
实现同样的接口,没接口CGLIB库可以生成一个类的子类(一个类的子类也可以用作该类的代理),用接口引用指向子类对象,代理类要调用目标类。
代理类可以进行测试,也可以和目标类通过配置文件切换,达到交叉业务。
AOP 面向方面的编程 涉及到代理,将业务模块化。
在方法内运行的内容前后加系统功能,可以将这些功能提取出来,放在方法前后。
运行结果是一样的。
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
在调用目标方法的前后,或异常处理上加上系统功能代码。
代理的理解:
本来客户端调用目标类
现在换成
客户端调用代理类,代理类中有个构造函数(接受handler对象)
handler是接口,可以用子类对象创建,子类中的方法invoke里
的方法调用(target)而target的内容就是各个方法的内容。
比如:你找代理的add方法,代理去找目标的add方法,而你在代理方法中
还可以加入日志方法。log(), 这样可以做一个框架,将代码以一个参数传进来。
在方法内传入一个对象,也就执行了对象的代码。
给InvocationHandler 2个对象 一个目标类的对象,一个系统功能的对象。
见ProxyTest.java类 Advice.java接口 MyAdvice类
package cn.itcast.day3;import java.lang.reflect.*;import java.util.*;/* * 获得动态类的构造方法和方法的列表。 * */public class ProxyTest {/** * @param args */public static void main(String[] args) throws Exception {// TODO Auto-generated method stubClass clazzProxy1 =Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);//先获得Proxy的字节码,(类加载器,实现的接口为接口的字节码)最后得到Class的字节码System.out.println(clazzProxy1.getName());System.out.println("----------begin constructors list-----------");Constructor[] constructors = clazzProxy1.getConstructors();for(Constructor constructor : constructors){String name = constructor.getName();StringBuilder sBuilder = new StringBuilder(name);sBuilder.append('(');//增加多个参数列表Class[] clazzParams = constructor.getParameterTypes();for(Class clazzParam : clazzParams){sBuilder.append(clazzParam.getName()).append(',');}//去掉最后一个',',要考虑如果无参数的情况if(clazzParams != null && clazzParams.length != 0)sBuilder.deleteCharAt(sBuilder.length()-1);sBuilder.append(')');System.out.println(sBuilder);}System.out.println("----------begin methods list-----------");Method[] methods = clazzProxy1.getMethods();for(Method method : methods){String name = method.getName();StringBuilder sBuilder = new StringBuilder(name);sBuilder.append('(');//增加多个参数列表Class[] clazzParams = method.getParameterTypes();for(Class clazzParam : clazzParams){sBuilder.append(clazzParam.getName()).append(',');}//去掉最后一个',',要考虑如果无参数的情况if(clazzParams != null && clazzParams.length != 0)sBuilder.deleteCharAt(sBuilder.length()-1);sBuilder.append(')');System.out.println(sBuilder.toString());}/* * $Proxy0----------begin constructors list-----------$Proxy0(java.lang.reflect.InvocationHandler)----------begin methods list-----------hashCode()add(java.lang.Object)clear()equals(java.lang.Object)toString()contains(java.lang.Object)addAll(java.util.Collection)iterator()size()toArray()toArray([Ljava.lang.Object;)remove(java.lang.Object)isEmpty()containsAll(java.util.Collection)removeAll(java.util.Collection)retainAll(java.util.Collection)isProxyClass(java.lang.Class)getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)getInvocationHandler(java.lang.Object)newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)getClass()wait()wait(long,int)wait(long)notify()notifyAll() * */System.out.println("-----begin create instance object开始创建实例对象-----");//clazzProxy1.newInstance();//会调用不带参数的构造方法,没有,所以得找有参数的构造方法Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);//得传个参数,而InvocationHandler是接口,得用子类实现class MyInvocationHandler1 implements InvocationHandler{public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubreturn null;}}//获得Collection对象Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());System.out.println(proxy1.toString());//nullproxy1.clear(); //清除集合内容,可以调用没返回值的方法//proxy1.size();//空指针异常,不可以调用有返回值的方法,因为它要去调用内部的invoke返回null,而size返回整数。Collection proxy2 = (Collection)constructor.newInstance(new MyInvocationHandler1());constructor.newInstance(new InvocationHandler(){public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubreturn null;}});//我们先找到类,再找到实例对象,//第三种方法获得实例对象, 这里创建了一个动态类了final ArrayList target = new ArrayList();Collection proxy3 = (Collection)getProty(target,new MyAdvice());Object obj = proxy3.add("zxx");//add会去找InvocationHandler,而返回结果给了代理//obj 相当于 Object 相当于 retVal,一个传递的过程proxy3.add("lhm");proxy3.add("bxd");System.out.println(proxy3.size());System.out.println(proxy3.getClass().getName());}//给InvocationHandler 2个对象 一个目标类的对象,一个系统功能的对象。生成一个Object代理private static Object getProty(final Object target,final Advice advice) {Object proxy3 = Proxy.newProxyInstance(target.getClass().getClassLoader(),/*new Class[]{Collection.class},*/target.getClass().getInterfaces(),new InvocationHandler(){//ArrayList target = new ArrayList();//InvocationHandler接口中invoke接受三个参数 objProxy对象,add方法,“abc”参数public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {/*long beginTime = System.currentTimeMillis();Object retVal = method.invoke(target, args);long endTime = System.currentTimeMillis();System.out.println(method.getName()+" runtime:"+(endTime-beginTime));return retVal;*///抽取了方法advice.beforeMethod(method);Object retVal = method.invoke(target, args);advice.afterMethod(method);return retVal;}});return proxy3;}}
package cn.itcast.day3;import java.lang.reflect.Method;public interface Advice { void beforeMethod(Method method); void afterMethod(Method method);}
package cn.itcast.day3;import java.lang.reflect.Method;public class MyAdvice implements Advice {long beginTime = 0;public void afterMethod(Method method) {// TODO Auto-generated method stubSystem.out.println("从传智播客上班了");long endTime = System.currentTimeMillis();System.out.println(method.getName()+" runtime:"+(endTime-beginTime));}public void beforeMethod(Method method) {// TODO Auto-generated method stubSystem.out.println("到传智播客学习了");beginTime = System.currentTimeMillis();}}
2,实现AOP功能的封装与配置
(1)工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。
其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中
对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象
的getProxy方法返回的对象。
(2)BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvice
(3)ProxyFactoryBean充当封装生成动态代理的工厂,需要为工厂类提高哪些配置参数信息?
目标
通知
(4)编写客户端应用:
编写实现Advice接口的类和在配置文件中进行配置
调用BeanFactory获取对象
思想:
(1)Object obj = BeanFactory.getBean("xxx"); 创建xxx实例对象,xxx通过配置文件修改。
如果是xxx=cn.itcast.ProxyFactoryBean 返回一个代理
再写代理的target,advice.
见BeanFactory.java ProxyFactoryBean.java MyAdvice.java
AopFrameworkTest.java config.properties
package cn.itcast.day3.aopframework;import java.io.*;import java.util.*;import cn.itcast.day3.*;public class BeanFactory {Properties props = new Properties();public BeanFactory(InputStream ips){try{props.load(ips);}catch(IOException e){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 blocke.printStackTrace();}//如果是代理,就创建代理类,不是就产生beanif(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)bean).getProxy();//如果是代理就产生advice target,把它们放到代理工厂里去产生代理proxy} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return proxy;}return bean;}}
package cn.itcast.day3.aopframework;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import cn.itcast.day3.*;public class ProxyFactoryBean {private Advice advice;private Object target;public Object getProxy() {// TODO Auto-generated method stub//给InvocationHandler 2个对象 一个目标类的对象,一个系统功能的对象。生成一个Object代理Object proxy3 = Proxy.newProxyInstance(target.getClass().getClassLoader(),/*new Class[]{Collection.class},*/target.getClass().getInterfaces(),new InvocationHandler(){//ArrayList target = new ArrayList();//InvocationHandler接口中invoke接受三个参数 objProxy对象,add方法,“abc”参数public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {/*long beginTime = System.currentTimeMillis();Object retVal = method.invoke(target, args);long endTime = System.currentTimeMillis();System.out.println(method.getName()+" runtime:"+(endTime-beginTime));return retVal;*///抽取了方法advice.beforeMethod(method);Object retVal = method.invoke(target, args);advice.afterMethod(method);return retVal;}});return proxy3;}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;}}
package cn.itcast.day3.aopframework;import java.io.*;public class AopFrameworkTest {/** * @param args */public static void main(String[] args)throws Exception {// TODO Auto-generated method stubInputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");Object bean = new BeanFactory(ips).getBean("xxx");System.out.println(bean.getClass().getName());}}
config.properties配置文件
xxx=java.util.ArrayList#xxx=cn.itcast.day3.aopframework.ProxyFactoryBeanxxx.advice=cn.itcast.day3.MyAdvicexxx.target=java.util.ArrayList
---------------------- android培训 java培训 期待与您交流! ----------------------
详细请查看 http://edu.csdn.net/heima
- 黑马程序员——高新技术(三)
- 黑马程序员——浅谈java中的高新技术(三)
- 黑马程序员——高新技术(一)
- 黑马程序员——高新技术(二)
- 黑马程序员——高新技术(一)
- 黑马程序员——高新技术(二)
- 黑马程序员——高新技术(枚举)
- 黑马程序员——高新技术(反射)
- 黑马程序员——高新技术(一)
- 黑马程序员——高新技术(二)
- 黑马程序员——高新技术(反射)
- 黑马程序员——高新技术(概述)
- 黑马程序员—java高新技术(一)
- 黑马程序员—java高新技术(1)
- 黑马程序员—java高新技术(2)
- 黑马程序员——黑马学习日志之二十一 Java高新技术(三)
- 黑马程序员---Java高新技术(三)--反射
- 黑马程序员--22--高新技术(三)
- Java使用Zip包压缩文件示例
- Android下用C编写动态库及使用动态库
- java面试题总结
- 解决mips-openwrt-linux-uclibc-g++.bin: environment variable "STAGING_DIR" not defined
- MeasureSpec介绍及使用详解
- 黑马程序员——高新技术(三)
- Building Coder(Revit 二次开发)- 关于楼板边界的重新思考
- linux下 lvm 磁盘扩容
- MS SQL 2005 Express Edition 安装报错 错误为 unit 'sp_sqlagent_get_startup_info' to component 'Agent XPs'.
- Shell脚本编程的常识
- Shell函数返回值
- CFileDialog设置多选时的一个问题
- vmware linux挂载windows共享文件夹
- Spring安全权限管理(Spring Security)