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


三、代理类的作用与原理及AOP概念:

AOP:Aspect oriented program 面向方面编程。
OOP:Object oriented program 面向对象编程。

四、动态代理:
要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!写成百上千个代理类,是不是太累!
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。

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

CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中
例如:
5.需要写一个示意代码进行辅助说明,
例如
Class proxy{
void sayHello(){
……….
try{
target.sayHello();
}catch(Exception e){
………..
}
………….
}
}

产生动态类的方法:
static Class<?>getProxyClass(ClassLoader,class<?>...interface)
//该方法返回一个类字节码,相当于生成了一个动态代理类,在方法中指定了该类的加载器,和实现的接口。
//该加载器通常用与接口相同的类加载器

示例:打印出动态代理类中的所有构造方法和方法

package cn.itcast.day3;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 ProxyTest {public static void main(String[] args)throws Exception{//getProxyClass()接收两个参数:加载器,实现的接口。Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);System.out.println(clazzProxy1.getName());//该类有什么构造方法System.out.println("----------begin constructor list");/*希望打印出的构造方法如下格式:* $Proxy()* $Proxy(InvocationHandldr,int)*/Constructor[] constructors=clazzProxy1.getConstructors();for(Constructor  constructor:constructors){String name=constructor.getName();StringBuilder sBuilder=new StringBuilder(name);sBuilder.append('(');Class[] clazzParams=constructor.getParameterTypes();//获得参数类型,返回的是Class类型的数组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());}System.out.println("----------begin methods list");/*希望打印出的构造方法如下格式:* $Proxy()* $Proxy(InvocationHandldr,int)* */Method[] methods=clazzProxy1.getMethods();for(Method  method:methods){String name=method.getName();StringBuilder sBuilder=new StringBuilder(name);sBuilder.append('(');Class[] clazzParams=method.getParameterTypes();//获得参数类型,返回的是Class类型的数组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());}//由刚才的构造方法列表得:动态类只有一个有一个参数的构造方法:com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)//创建动态类 的实例对象及调用其方法。System.out.println("----------begin create instance list");//clazzProxy1.newInstance();因为动态类没有无参数的构造方法,所有这样new对象错误。//所以先得到构造方法Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class);//由得到的构造方法创建动态类的实例对象时需要指定一个InvocationHandler类型的对象,//但通过API查  询,InvocationHandler为一个接口,不能创建对象,所以要通过子类实现该接口,然后创建对象。class MyInvocationHandler1 implements InvocationHandler{@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubreturn null;}}//创建代理对象方式1Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler1());System.out.println(proxy1);//此处打印为null,原因可能有2个:1。该对象真的为null,但是这样会返回空指针异常//2.proxy1.toString()返回是null,显然是这种情况。//创建代理对象方式2/*对于上述通过实现接口来new对象,我们可以通过构造匿名内部类的方式,更简单*/Collection proxy2=(Collection)constructor.newInstance(new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubreturn null;}});//创建代理对象方式3,不需要先创建代理类再创建对象,采用直接调用Proxy.newProxyInstance方式创建对象。Collection proxy3=(Collection)Proxy.newProxyInstance(Collection.class.getClassLoader(), new Class[]{Collection.class},new InvocationHandler(){ArrayList target=new ArrayList();//此处的ArrayList起到了目标的作用,//暂时替代Collection对象。然后将运算后的结果返回给Collection对象,这样就相当于Collection对象自己调用一样。//代理对象,方法,传递的参数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()+"running time of"+(endTime-beginTime));return retVal;}});proxy3.add("zxx");//调用代理内部的invoke方法,并把proxy对象,add方法,"zxx"参数传递进去,代理内部执行完毕后再返回值。proxy3.add("lhm");System.out.println(proxy3.size());//注意:对于代理身上的方法,只有hashCode(),equals(),toString()三个方法交给InvocationHandldr去做。//而其他方法的实现,代理会自己实现。/*编写可生成代理和插入通告的通用方法。* 由上段代码我们可知:在代理类中新建对象的Invocation内部,代码是硬写上去的,不利于以后的修改。* 我们可以采用在其内部接收一个对象的方式来进行构造,而这个对象是由外部一个类传过来的,这个类中任意定义需要的代码,框架思想。* */final ArrayList target=new ArrayList();//注意:在内部类的方法中要访问局部变量,必须加finalCollection proxy4=(Collection)getProxy(target,new MyAdvice());//要想得到此方法,可以将上段产生代理对象的方法,Refactor-Extract method抽取方法得到。proxy4.add("ljx");//proxy4.add("xyk");//System.out.println(proxy4.size());}private static Object getProxy(final Object target,final Advice advice) {Object proxy4=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 {/*long beginTime=System.currentTimeMillis();Object retVal=method.invoke(target, args);long endTime=System.currentTimeMillis();System.out.println(method.getName()+"running time of"+(endTime-beginTime));return target;*/advice.beforeMethod(method);Object retVal=method.invoke(target, args);advice.afeterMethod(method);return target;}});return proxy4;}}

五、  实现类似spring的可配置的AOP框架

一、工厂类BeanFactory:

1、工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。

2、getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则返回该类示例对象的getProxy方法返回的对象。

3、BeanFactory的构造方法接收代表配置文件的输入流对象的配置文件格式如下:

#xxx=java.util.ArrayList

xxx=cn.itcast.test3.aopframework.ProxyFactoryBean

xxx.advice=cn.itcast.test3.MyAdvice

xxx.target=java.util. ArrayList

注意:其中的#代表注释当前行。

4、ProxyFactoryBean充当封装成动态的工厂,需为工厂提供的配置参数信息包括:

目标(target)

通告(advice)

5、BeanFactory和ProxyFactoryBean:

1)BeanFactory是一个纯粹的bean工程,就是创建bean即相应的对象的工厂。

2)ProxyfactoryBean是BeanFactory中的一个特殊的Bean,是创建代理的工厂。

二、实现类似spring的可配置的AOP框架的思路:

1、创建BeanFactory类:

1)构造方法:接受一个配置文件,通过Properties对象加载InputStream流对象获得。

2)创建getBean(String name)方法,接收Bean的名字,从上面加载后的对象获得。

3)通过其字节码对象创建实例对象bean。

4)判断bean是否是特殊的Bean即ProxyFactoryBean,如果是,就要创建代理类,并设置目标和通告,分别得到各自的实例对象,并返回代理类实例对象。如果不是在返回普通类的实例对象。

2、创建ProxyFactoryBean(接口),此处用类做测试,其中有一个getProxy方法,用于获得代理类对象。

3、对配置文件进行配置,如上面配置一样。

4、作一个测试类:AopFrameworkTest进行测试。

主要程序:

//创建BeanFactory类
package cn.itcast.test3.aopframework;
import java.io.*;
import java.util.Properties;
import cn.itcast.test3.Advice;
public class BeanFactory {Properties prop = new Properties();//创建对象时需要传入一个配置文件中的数据,所以需要在构造方法中接受一个参数public BeanFactory(InputStream ips) {try {//将配置文件加载进来prop.load(ips);} catch (IOException e) {e.printStackTrace();}}//创建getBean方法,通过配置文件中的名字获取bean对象public Object getBean(String name){//从配置文件中读取类名String className = prop.getProperty(name);Object bean = null;try {//由类的字节码获取对象Class clazz = Class.forName(className);bean = clazz.newInstance();} catch (Exception e) {e.printStackTrace();} //判断bean是特殊的bean即ProxyFactoryBean还是普通的beanif(bean instanceof ProxyFactoryBean){Object proxy = null;try {//是ProxyFactoryBean的话,强转,并获取目标和通告ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;//获取advice和targetAdvice advice = (Advice)Class.forName(prop.getProperty(name + ".advice")).newInstance();Object target = Class.forName(prop.getProperty(name + ".target")).newInstance();//设置目标和通告proxyFactoryBean.setAdvice(advice);proxyFactoryBean.setTarget(target);//通过类ProxyFactoryBean(开发中是作为接口存在)中获得proxy对象proxy = proxyFactoryBean.getProxy();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} //是ProxyFactoryBean的话,返回proxy对象return proxy;}//否则返回普通bean对象return bean;}
}//创建ProxyFactoryBean类
package cn.itcast.test3.aopframework;
import java.lang.reflect.*;
import cn.itcast.test3.Advice;
public class ProxyFactoryBean {private Object target;private Advice advice;public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}public Advice getAdvice() {return advice;}public void setAdvice(Advice advice) {this.advice = advice;}public Object getProxy() {Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),//这里的接口要和target实现相同的接口target.getClass().getInterfaces(),new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//通过契约,使用其方法--before和after方法advice.beforeMethod(method);Object value = method.invoke(target, args);advice.afterMethod(method);return value;}});return proxy;}
}
//创建测试类AopFrameworkTest
package cn.itcast.test3.aopframework;
import java.io.InputStream;
public class AopFramewrorkTest {public static void main(String[] args)throws Exception {//读取配置文件的数据InputStream ips = AopFramewrorkTest.class.getResourceAsStream("config.property");//获取bean对象Object bean = new BeanFactory(ips).getBean("xxx");System.out.println(bean.getClass().getName());}

转载于:https://www.cnblogs.com/yun45/archive/2013/05/15/3080059.html

黑马程序员_Java高新技术--代理相关推荐

  1. 黑马程序员-java高新技术-代理和类加载器

    ------- android培训. java培训.期待与您交流! ---------- 代理模式:为其他对象提供一种代理以控制对这个对象的访问.说白了就是,在一些情况下客户不想或不能直接引一个对象, ...

  2. 黑马程序员_Java高新技术3(框架,JavaBeans与内省(Introspector)) - 伊秋

    1.Java框架(frame) /* 通俗例子:我做房子(框架)卖给用户住,由用户自己安装门窗和空调(用户自定义类/用户自定义其它信息)用户需要使用我的房子(框架),把符合框架中结构的门窗插入进我提供 ...

  3. 黑马程序员_java高级篇网络编程TCP实战Day8(上)

    ---------------------ASP.Net+Android+IOS开发.Net培训.期待与您交流! ----------- 黑马程序员_java高级篇网络编程TCP实战Day8(上) ( ...

  4. 黑马程序员_java自学学习笔记(八)----网络编程

    黑马程序员_java自学学习笔记(八)----网络编程 android培训. java培训.期待与您交流! 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无 ...

  5. 黑马程序员_JAVA相关基础知识

    ------- android培训.java培训.期待与您交流! -------- JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便 ...

  6. 黑马程序员_Java解析网络数据流的三种特殊方法

    Java解析网络数据流的三种特殊方法 Java作为最开放的语言,已越来越受到网络程序员的青睐.但这一青睐族有着同样的经历--曾经都为网络上通信的Java数据格式而烦恼. 笔者也不例外,曾经为此而查阅了 ...

  7. 黑马程序员_Java基础Day05_面向对象之封装(Done)

    ------- android培训.java培训.期待与您交流! ---------- Day05开始接触到了Java核心部分--"面向对象". 面向对象是一种思考思想,是相对于早 ...

  8. 黑马程序员_Java基础_前期准备02-1

    ---------------------------------------- JavaEE+云物联.期待与您交流!----------------------------------------- ...

  9. 黑马程序员_java基础笔记(03)...面向对象

    1:面向对象的概念,2 : 类和对象的关系,3 : 封装,4 : 构造函数,5 : this关键字,6 : static关键字, 7 : 单例设计模式,8 : 继承,9 : 抽象类,10 : 接口,1 ...

最新文章

  1. CAS SSO使用指南
  2. Vue计算属性和监听属性
  3. 解决 maven 项目中加入了 lombok 库后依然报错的问题
  4. 出租车管理系统java_基于jsp的出租车管理系统-JavaEE实现出租车管理系统 - java项目源码...
  5. php mysql group by_php – 如何在mysql查询中解决“不在GROUP BY中”错误
  6. igmp是哪个层协议_【干货】IGMPv1协议闲聊
  7. 压缩与解压2---文件的压缩
  8. Cognos函数(六) - total的使用
  9. 生鲜电商带火冷链物流,中、圆、申三通如何拼了命地排兵布阵
  10. VPP /什么是VPP?
  11. 【舆情分析(5)】 情感倾向分析之鲁迅《祝福》里对祥林嫂(特定人物)的情感倾向
  12. 深度学习英文缩写_深度学习相关专业词汇简称汇总
  13. 项目管理-1-忆往昔
  14. 使用vue-cli脚手架初始化Vue项目下的项目结构
  15. Linux学习笔记(二十三) -- QT的安装和卸载
  16. Kubernetes:基于命令行终端UI的管理工具 K9s
  17. (七)北斗定位和伽利略定位
  18. 小孩发烧怎么办 - 强烈建议查看转载内容的详情,看视频介绍
  19. mp3如何转换为wav_将WAV转换为MP3或MP3转换为WAV
  20. 【python】你的连连看为啥子如此之快,原来你开全自动了呀!!

热门文章

  1. (写给应届生)学松下幸之助找工作
  2. 搭建企业分支机构(单域多站点)虚拟网络之W2k3 (一) 初稿
  3. 化解恶劣情绪山人自有妙计
  4. ie浏览器打开aspx文件乱码_ie浏览器下载文件时文件名乱码
  5. vscode 语法检查_Jenkins 声明式流水线的语法错误检查
  6. linux系统检测脚本,脚本检测linux系统资源
  7. php psr 编码规范_PHP编码风格规范
  8. mysql的set架构_MYSQL 整体架构浅析
  9. css开头的文本格式,css文件开头怎么写
  10. 圆 最小外包矩形_【OpenCV3图像处理】提取轮廓的凸包、外包矩形、最小外包矩形、最小外包圆...