您的位置:首页 > 职场人生

黑马程序员————java代理学习笔记

2014-10-08 14:06 274 查看
     -----------android培训java培训、java学习型技术博客、期待与您交流!------------
代理的作用:为已经存在的多个有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理、日志、计算方法的运行时间、事物管理、等等。

客户端以前是直接调用的Target,现在不让客户端直接调用Target,让它调用代理类Proxy

代理类Proxy和目标类Target实现相同的接口,也就是说对外有相同的方法,在客户端编写程序的时候不是引用代理也不是引用目标而是引用接口。

代理类:一定要调用目标中的方法,并且可以再调用的方法的前面和后面可以添加一些额外功能的代码

采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中使用目标类、还是代理类,这样以后以后很容易切换,比如想要日志功能时就配置代理类,否者就配置目标类。这样,增加系统的功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。

静态代理类实现过程:

//创建一个静态代理
/*1.创建一个目标类,实现一个Subject接口
* 2.创建一个代理类实现相同的Subject接口
* 3.创建一个工厂类,让代理类与目标类之间实现关联
* */
public class ProxyDemo {
public static void main(String[] args){
//用代理的方式调用目标类RealSubject中的类的方法
Subject realSubject=new RealSubject();
ProxySubject ps=FactorySubject.getInstance(realSubject);
ps.speak();
}
}
//创建一个接口
interface Subject{
//声明-其中的方法
public void speak();
public void run();
}
//创建一个目标类
class RealSubject implements Subject{
RealSubject(){}
@Override
public void speak(){
System.out.println("目标类");
}
public void run(){
System.out.println("目标类运行");
}
}
//创建代理类
class ProxySubject implements Subject{
//代理类的作用就是可以调用目标类中的方法并且在该方法前和后增加额外的方法
private Subject target;
ProxySubject(Subject target){
this.target=target;
}

public void speak(){
System.out.println("代理类额外功能");
target.speak();
}
public void run(){
System.out.println("代理类额外功能");
target.run();
}

}
//创建一个工厂将代理类与目标类联系起来
class FactorySubject{
public static ProxySubject  getInstance(Subject proxied){
return new ProxySubject(proxied);
}
}


Aop:面向方面编程:代理是实现Aop功能的核心和关键技术。

1》系统中村在交叉业务,一个交叉业务就要切入到系统中的一个方面

2》Aop的目标就是要使交叉业务模块化,可以采用将切面代码移动到原始方法的前后(就是在原始方法的前面或后面添加代码)这与直接在方法中编写切面代码的运行效果是一样的。

动态代理出现的原因:要为系统中的各种接口增加代理功能,那就需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!

动态代理原理:

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

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

3》要用cglib库才能生成没有接口的类的子类

动态代理类java.lang.reflect.Proxy

该类的特有方法都为静态方法:

1》
getProxyClass(ClassLoader loader,Class<?>... interfaces)
 返回代理类的Class对象

分析:在jvm内存里面创建出来的字节码没有通过classLoader加载但是也要为它指定一个类加载器,那么在创建的时候就要为他们指定一个类加载器加载

@分析该动态生成的代理类是什么类,它有哪些构造方法

package test2;
import java.lang.reflect.*;
import java.util.Collection;
public class ProxyTest {

public static void main(String[] args) {
// TODO 自动生成的方法存根
Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class.getInterfaces());
System.out.println(clazzProxy1.getName());//该类的类类型为$Proxy0
//得到所有该代理类的所有的构造方法
Constructor[] constructors=clazzProxy1.getConstructors();
for(int i=0;i<constructors.length;i++){
System.out.println(constructors[i]);//该类只有一个构造方法public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
}
 }

}
分析动态代理类生成过程:
package test2;
import java.lang.reflect.*;
import java.util.Collection;
public class ProxyTest {

public static void main(String[] args) throws Exception, SecurityException {
// TODO 自动生成的方法存根
Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class.getInterfaces());
System.out.println(clazzProxy1.getName());//该类的类类型为$Proxy0
//得到所有该代理类的所有的构造方法
Constructor[] constructors=clazzProxy1.getConstructors();
for(int i=0;i<constructors.length;i++){
System.out.println(constructors[i]);//该类只有一个构造方法public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
//通过反射创建该$Proxy类的实例对象
MyInvocationHandler1 handler=new MyInvocationHandler1();
Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class);
Collection $proxy0=(Collection)constructor.newInstance(handler);
//System.out.println($proxy0);
System.out.println($proxy0.getClass());

}
}

}
class MyInvocationHandler1 implements InvocationHandler{
MyInvocationHandler1(){}
public Object invoke(Object proxy, Method method, Object[] args) {
return null;

}
}
动态代理实际应用:

第一种方式:

1.创建MyInvocationHandler()实现InvocationHandler接口:

class MyInvocationHandler implements InvocationHandler{
private Object subject;
MyInvocationHandler(Object subject){
this.subject=subject;
}
public Object invoke(Object proxy,Method method,Object[] args)throws Exception {
long time1=System.currentTimeMillis();//返回当前时间
//args[0]="hehe";
Object obj=method.invoke(subject, args);

long time2=System.currentTimeMillis();//返回当前时间
System.out.println(time2-time1);//获得方法运行的时间
return obj;
}
}


2.在main方法中创建要代理类的实例对象a

3.建立InvocationHandler的实例对象并将a作为参数传递给MyInvocation;

ArrayList arr=new ArrayList();
InvocationHandler handler=new MyInvocationHandler(arr);


4.调用类Proxy中的newProxyInstance(handler类加载器、代理类要实现的接口、handler)

List list=(List)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
ArrayList.class.getInterfaces(),
handler);
5.用代理的方式调用目标类中的方法。

//调用代理中的方法
list.add("haha");//用代理的方式给集合arr添加元素
System.out.println(arr);
System.out.println(arr.getClass());//动态生成的代理类


用匿名内部类的方法简化代码书写:
InvocationHandler handler=new InvocationHandler(){//匿名内部类产生
//private Object subject;

public Object invoke(Object p
4000
roxy,Method method,Object[] args)throws Exception {
long time1=System.currentTimeMillis();//返回当前时间
//args[0]="hehe";
Object obj=method.invoke(target, args);

long time2=System.currentTimeMillis();//返回当前时间
System.out.println(time2-time1);//获得方法运行的时间
return obj;
编写可生成代理和插入通告的通用方法

1.将生成代理类的方法单独提取出来

class ProxyTarget{
private static Object target;
ProxyTarget(Object target){
this.target=target;
}
public static Object getProxy(){

InvocationHandler handler=new InvocationHandler(){//匿名内部类产生
//private Object subject;

public Object invoke(Object proxy,Method method,Object[] args)throws Exception {
long time1=System.currentTimeMillis();//返回当前时间
//args[0]="hehe";
Object obj=method.invoke(target, args);

long time2=System.currentTimeMillis();//返回当前时间
System.out.println(time2-time1);//获得方法运行的时间
return obj;
}
};
return Proxy.newProxyInstance(handler.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);

}

}
综合应用:
package test2;
/*写一个ArrayList类的代理,其内部实现和ArrrayList中完全相同的功能,并可以计算每个方法运行的时间
*
* */
import java.lang.reflect.*;
import java.util.*;
public class Test3 {

public static void main(String[] args) {
// TODO 自动生成的方法存根
ArrayList arr=new ArrayList();
InvocationHandler handler=new MyInvocationHandler(arr);
//一次性生成代理
List list=(List)Proxy.newProxyInstance(handler.getClass().getClassLoader(), ArrayList.class.getInterfaces(), handler);
//调用代理中的方法 list.add("haha");//用代理的方式给集合arr添加元素 System.out.println(arr); System.out.println(arr.getClass());//动态生成的代理类
System.out.println("===============第二种动态代理方式==============");
ProxyTarget pt=new ProxyTarget(arr);
List list1=(List)pt.getProxy(new MyAdvice());
//用动态代理调用代理类中的方法
list1.add("我是getProxy产生的动态代理类");
System.out.println(arr);

}

}
class MyInvocationHandler implements InvocationHandler{ private Object subject; MyInvocationHandler(Object subject){ this.subject=subject; } public Object invoke(Object proxy,Method method,Object[] args)throws Exception { long time1=System.currentTimeMillis();//返回当前时间 //args[0]="hehe"; Object obj=method.invoke(subject, args); long time2=System.currentTimeMillis();//返回当前时间 System.out.println(time2-time1);//获得方法运行的时间 return obj; } }
class ProxyTarget{
private static Object target;
ProxyTarget(Object target){
this.target=target;
}
public static Object getProxy(final Advice advice){

InvocationHandler handler=new InvocationHandler(){//匿名内部类产生
//private Object subject;

public Object invoke(Object proxy,Method method,Object[] args)throws Exception {
advice.beforeMethod(method);

Object obj=method.invoke(target, args);
advice.afterMethod(method);

return obj;
}
};
return Proxy.newProxyInstance(handler.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);

}

}
//将插入通告的方法提取出来
//建立通告接口
interface Advice{
public void afterMethod(Method method);
public void beforeMethod(Method method);

}
//实现通告接口
class MyAdvice implements Advice{
MyAdvice(){}
long time1;
long time2;
public void afterMethod(Method method){
System.out.println("通告代码,方法运行后");
long time2=System.currentTimeMillis();//返回当前时间
System.out.println("运行时间:"+(time2-time1));//获得方法运行的时间
}
public void beforeMethod(Method method){
System.out.println("通告代码,方法运行前");
long time1=System.currentTimeMillis();//返回当前时间
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: