高新技术之代理

来源:互联网 发布:好听的编程项目名称 编辑:程序博客网 时间:2024/06/02 11:11


代理

生活中的代理:

  词面意思:

        1. [act as agent]:短时间代人担任职务

  2. [act for]:受委托代表当事人进行某种活动。

 

      比如说你想把一份礼物送给某公司的董事长,不需要直接交给董事长,而是交给她的秘书,她的秘书帮忙查看这个礼物是不是危险物品,不是就转交给董事长,这就是代理


程序中的代理:
    有一个类已经开发好了,我们要为这个类增加功能,比如说异常处理,日志输出,执行时间等,前提是这个类得方法没有给你,这个时候就需要用到代理了。代理就是在目标的前后增加功能。

代理的重要原则:不要把供货商暴露给你的客户。
图解:

 

代理类生成及其原理:

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

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

原因:
          告诉动态代理类需要实现的方法(接口中方法),所以这个类没有接口就不能实现代理,除非用CGLIB库动态生成这个类的子类(非官方)


代理类具有以下属性:
代理类是公共的、最终的,而不是抽象的。
未指定代理类的非限定名称。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留。 
代理类会按同一顺序准确地实现其创建时指定的接口。 
每个代理类都有一个可以带一个参数(接口 InvocationHandler 的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance 方法(将调用 Proxy.getProxyClass 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。
如:

创建某一接口 Foo 的代理:

     InvocationHandler handler = new MyInvocationHandler(...);
     Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });
     Foo f = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });
 或使用以下更简单的方法:
     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class[] { Foo.class },
                                          handler);

第一个参数:传类加载器,因为动态代理是从内存中出来的,没有类加载器,所以要给它指定一个加载器。

第二个参数:类的接口,告诉动态代理类需要实现的方法(接口中的方法),接口可以是多个,所以设置是可变参数。

第三个参数:invocationHandler,必须实现这个接口才能是代理类正常工作。

 

如果代理接口包含某一方法,它的名称和参数签名与 java.lang.Object 的 hashCode、equals 或 toString 方法相同,那么在代理实例上调用这样的方法时,传递到调用处理程序的 Method 对象将使 java.lang.Object 成为其声明类。(意思是说代理类调用Object里面的方法的时候,除了hashCode(),equals()或toString()这三个方法外都不会交给handler,而直接使用原有方法.)

代理类调用流程:

AOP: Aspect Oriented Programming 面向切面编程。

  面向切面编程也叫面向方面:Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

  AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面(方面)编程。

  主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。

  主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

  

 

自己写的代理代码


//Bean工厂
public class BeanFactory {
 Properties pros = new Properties();
 public BeanFactory(InputStream is){
  try {
   pros.load(is);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 public Object getBean(String name){
  //根据键拿到值,这里拿到的是类名
  String className = pros.getProperty(name);
  Object bean = null;
  try {
   //实例化此类
   bean = Class.forName(className).newInstance();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  //判断是否为代理工厂
  if(bean instanceof ProxyFactory){
   
   ProxyFactory proxyFactory = (ProxyFactory)bean;
   Object proxy = null;
   try {
    //使用反射把advice和target键所对应的类实例化,并设置进代理工厂
    proxyFactory.setAdvice((Advice) Class.forName(pros.getProperty(name+".advice")).newInstance());
    proxyFactory.setTarget(Class.forName(pros.getProperty(name+".target")).newInstance());
    //拿到代理类
    proxy = proxyFactory.getProxy();
   } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return proxy;
   
  }
  return bean;
 }
}

//代理工厂

public class ProxyFactory {
 private Advice advice ;
 private Object target;
 public ProxyFactory(){
 }
 
 //代理方法
 public Object getProxy(){
  //创建代理类(传入目标的类加载器,目标实现的接口)
  Object proxy1 = Proxy.newProxyInstance(target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new InvocationHandler() {
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {
      //在方法执行前线调用建议类的方法before();
      advice.before();
      //调用方法,此方法的对象是target。
      Object o = method.invoke(target, args);
      //在方法执行后调用建议类的方法after();
      advice.after();
      //返回执行完方法后返回的结果
      return o;
     }
    });
  //返回代理类
  return proxy1;
 }
 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;
 }
 
}

 

//我的建议类,继承建议类

public class MyAdvice implements Advice{

// 定义两个方法,分别处理代理前后操作
 public void after() {
  // TODO Auto-generated method stub
  System.out.println("33");
 }
 public void before() {
  // TODO Auto-generated method stub
  System.out.println("22");
 }

}

 

//定义接口的好处在于当有多个类时,他们都实现你这个接口,你就可以把类里面的变量改为Adivce,让他来引用子类对象,这样当你要换类的时候,可以直接在配置文件那里改而不需要再在类里面改变量名字了。

public interface Advice {

 public void before();

 public void after();

}

 

//测试类

public class Test {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  //InputStream is = Test.class.getResourceAsStream("config.properties");
  //取得配置文件的输入流
  InputStream is = Test.class.getClassLoader().getResourceAsStream("beanFactory/config.properties");
  //拿到bean
  Object bf = new BeanFactory(is).getBean("xxx");

// 代理类不会调用invoke
  System.out.println(bf.getClass().getName());

//代理类会调用invoke,因为bf相当于bf.toString().

System.out.println(bf);
 }

}

 

properties文件

#xxx=java.util.ArrayList
xxx=beanFactory.ProxyFactory
xxx.advice=beanFactory.MyAdvice
xxx.target=java.util.ArrayList

 

 


原创粉丝点击