黑马程序员-----动态代理
2014-03-08 18:54
381 查看
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
一、代理简介
生活中的代理:
武汉人从武汉的代理商手中买联想电脑和直接跑到北京联想总部买电脑,它们最终的主体业务目标相同,但是还是又去别的
程序中的代理
1、要为已存在的多个具有相同接口的目标类 的各个方法增加一些系统功能;
2、编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码
3、如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易;
二、AOP:交叉业务的编程问题即为面向方面的编程,简称AOP,AOP目标就是要使交叉业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的;
OOP:面向对象的编程;
注意:代理是实现AOP功能的核心和关键技术;
三、动态代理技术
1、要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情;
2、JVM可以在运行期动态生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
3、JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理;
4、CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库;
5、代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统代码:
a、在调用目标方法之前
b、在调用目标方法之后
c、在调用目标方法之前后
d、在处理目标方法异常的catch块中
三、分析JVM动态生成的类
public class ProxyTest {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
System.out.println("------Constructor 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.toString());
}
System.out.println("------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());
}
System.out.println("------methods list-------");
//clazzProxy1.newInstance();//Proxy类没有无参的构造方法所以不能调用newInstance方法
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
Collection proxy = (Collection) constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
System.out.println(proxy);//Collection类对象proxy调用方法toString返回值为null;
Collection proxy1 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler(){
ArrayList target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*Collection对象每调用一次方法invoke方法就执行一次
Collection接口中的方法的运行原理
int size(){
return handler.invoke(this,this.getMethod("size"),null);
}*/
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;
}
}
);
proxy1.add("aaa");
proxy1.add("bbb");
proxy1.add("ccc");
System.out.println(proxy1.size());
}
}
让java虚拟机(JVM)创建动态类及其实例对象需要提供的信息:
1、生成的类中有哪些方法,同归哦让其实现哪些接口的方式进行告知;这个类实现了哪些接口
2、产生的类字节码必须有一个关联的类加载器对象;
3、生成的类中的方法的代码是怎样的,也得由我们提供。把我们的代码写在一个约定好了接口对象的方法中,把对象传给它,它调用我的方法,即相当于插入了我的代码。提供执行代码的对象就是那个InvocationHandler对象,它是在创建动态类的实例对象的构造方法时传递进去的。在上面的InvocationHandler对象的invoke方法中加一点代码,就可以看到这些代码被调用运行了
invoke方法接收的三个参数的意思:当前正在调用方法的代理对象,代理对象调用的方法,方法接收的参数;
class Proxy{
add(Object obj){
return handler.invoke(Object proxy,Method method,Object[]args);
}
}
四、动态代理工作原理
客户端调用代理,代理的构造方法接受一个handler对象,客户端调用代理的各个方法,代理的各个方法会把调用请求转发给刚才通过构造方法传进去的handler对象,这个handler对象又把各个请求分发给目标的相应方法;handler的invoke方法中可以加入日志功能,还可以调用目标的对应方法;
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流!
----------------------
详细请查看:<a href="http://edu.csdn.net" target="blank">http://edu.csdn.net</a>
一、代理简介
生活中的代理:
武汉人从武汉的代理商手中买联想电脑和直接跑到北京联想总部买电脑,它们最终的主体业务目标相同,但是还是又去别的
程序中的代理
1、要为已存在的多个具有相同接口的目标类 的各个方法增加一些系统功能;
2、编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码
3、如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易;
二、AOP:交叉业务的编程问题即为面向方面的编程,简称AOP,AOP目标就是要使交叉业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的;
OOP:面向对象的编程;
注意:代理是实现AOP功能的核心和关键技术;
三、动态代理技术
1、要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情;
2、JVM可以在运行期动态生成类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
3、JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理;
4、CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库;
5、代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统代码:
a、在调用目标方法之前
b、在调用目标方法之后
c、在调用目标方法之前后
d、在处理目标方法异常的catch块中
三、分析JVM动态生成的类
public class ProxyTest {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
System.out.println("------Constructor 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.toString());
}
System.out.println("------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());
}
System.out.println("------methods list-------");
//clazzProxy1.newInstance();//Proxy类没有无参的构造方法所以不能调用newInstance方法
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
Collection proxy = (Collection) constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
System.out.println(proxy);//Collection类对象proxy调用方法toString返回值为null;
Collection proxy1 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler(){
ArrayList target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*Collection对象每调用一次方法invoke方法就执行一次
Collection接口中的方法的运行原理
int size(){
return handler.invoke(this,this.getMethod("size"),null);
}*/
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;
}
}
);
proxy1.add("aaa");
proxy1.add("bbb");
proxy1.add("ccc");
System.out.println(proxy1.size());
}
}
让java虚拟机(JVM)创建动态类及其实例对象需要提供的信息:
1、生成的类中有哪些方法,同归哦让其实现哪些接口的方式进行告知;这个类实现了哪些接口
2、产生的类字节码必须有一个关联的类加载器对象;
3、生成的类中的方法的代码是怎样的,也得由我们提供。把我们的代码写在一个约定好了接口对象的方法中,把对象传给它,它调用我的方法,即相当于插入了我的代码。提供执行代码的对象就是那个InvocationHandler对象,它是在创建动态类的实例对象的构造方法时传递进去的。在上面的InvocationHandler对象的invoke方法中加一点代码,就可以看到这些代码被调用运行了
invoke方法接收的三个参数的意思:当前正在调用方法的代理对象,代理对象调用的方法,方法接收的参数;
class Proxy{
add(Object obj){
return handler.invoke(Object proxy,Method method,Object[]args);
}
}
四、动态代理工作原理
客户端调用代理,代理的构造方法接受一个handler对象,客户端调用代理的各个方法,代理的各个方法会把调用请求转发给刚才通过构造方法传进去的handler对象,这个handler对象又把各个请求分发给目标的相应方法;handler的invoke方法中可以加入日志功能,还可以调用目标的对应方法;
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流!
----------------------
详细请查看:<a href="http://edu.csdn.net" target="blank">http://edu.csdn.net</a>
相关文章推荐
- 黑马程序员之java语言,及环境搭建
- 黑马程序员 张老师 面试题讲解 银行调度系统
- [转载]求职者防骗必读!楼主亲身经历告诉你岗前培训多么不靠谱而且违法!
- 程序员的奋斗史(三十六)——人在囧途之应聘篇(六)——第一季终结篇
- 《黑马程序员》 银行业务调度系统案例分析与总结
- 《黑马程序员》 交通灯管理系统案例分析与总结
- 图像处理职位面试题汇总(4)
- 黑马程序员——String类知识点详细
- 财经管理] 《你为什么越忙越穷》(揭示职场成功奥秘
- c# 常用的面试题
- 黑马程序员-----类加载器
- 8. 微软面试题:翻转句中的英文单词的顺序
- 《程序员面试题精选》03.子数组的最大和
- 链表面试题小结
- 谷歌史上15个最让求职者抓狂的面试题
- 《黑马程序员》 枚举类之交通灯示例分析
- 趣谈程序员
- 送给前线码农的话 – 大牛们的经典语录---摘抄了不少经典的好词好段,虽是只言片语,但都是心得。(转)
- [LeetCode]Reverse Words in a String 新题151
- 华为面试经历