黑马程序员-动态代理

---------------------- android培训java培训、期待与您交流! ----------------------

代理的概念与作用:

程序中的代理:

    1.  要为已存在的多个具有相同接口的目标类的方法增加一些系统功能。如:异常处理、日志等等。

    2.  编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法是加上系统功能的代码

    3.  如果采用工厂模式和配置文件的方法进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是代理类。这样,以后很容易切换。

动态代理技术:

    1.  要为系统中各种接口的类增加代理功能,那将需要太多的代理类全部采用静态代理方法,全部采用静态代理方式,非常麻烦。

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

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

    4.  CGLIB库可以动态的生成一个类的子类,一个类的子类也可以用作该类的代理,所以,乳沟一个没有实现接口的类的城池动态代理类,那么可以使用CGLB库。

    5.  代理类的各个方法中通常除了调用目标的相应方法和外观返回目标返回到结果外,还可以在代理方法中的如下四个位置加上系统功能代码:

    a)    在调用目标方法之前

    b)   在调用目标方法之后

    c)   在调用目标方法前后

    d)   在处理目标方法异常的catch块中

JVM创建动态类及查看其方法:

    1.  java.lang.reflect Proxy的方法获得代理类的字节码:static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)

          返回代理类的 java.lang.Class对象,并向其提供类加载器和接口数组。

    2.  查看动态类的构造方法和继承的接口中的方法。

    3.  没有无参数的构造方法。

创建动态类的实例对象及其方法:

    4.  通过Class对象得到构造方法

    5.  创建实现java.lang.reflect 接口 InvocationHandler的类

    6.  InvocationHandler对象作为构造函数参数传入

分析动态生成的类的内部代码及InvocationHandler对象的运行原理:

    1.  动态生成的类实现接口(可以多个),生成的类有接口的所有方法和一个接收InvocationHandler参数的构造方法。

    2.  传递的InvocationHandler对象作为参数为动态类的属性初始化。

    3.  实现接口的动态类的方法其实就是在调用InvocationHandler对象的invoke(Object proxyMethod methodObject[] args)方法,

    4.  invoke方法内部通过调用动态类的方法作用于目标对象method.invoke(Object targetObject … args).

让动态生成的类成为目标类的代理:

     1.  怎样将目标类传进去?让匿名的InvocationHandler实现类访问外面方法中的目标类实例对象的final类型的引用变量。

     2.  将系统功能封装在实现Advice接口的类中,将类的对象传进去。

     3.  将创建代理类的过程改为一种更优雅的方式,eclipse重构出一个getProxy方法,绑定接收目标和Advice同时返回代理对象。

实现AOP功能的封装与配置:

      要求:

     1.  工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换,其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类实例对象,否则,返回该类实例对象的getProxy方法返回的对象。

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

            xxx=java.util.ArrayList                                              

            xxx=.ProxyFactoryBean

            xxx.target=java.util.ArrayList

            xxx.advice=.MyAdvice

     3.  ProxyFactoryBean充当封装生成动态代理的工厂,需要为工厂提供:

         a)    目标类Target

         b)   通知Advice

     4.  编写客户端:

        a)    编写实现Advice接口的类和在配置文件中配置

        b)    调用BeanFactory获取对象

练习:

package org.cc.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
/*
 * 生成代理类的工厂
 */
public class ProxyFactoryBean {
 private Object target;//接收目标类
 private Advice advice;//接收要执行的系统功能

 public void setTarget(Object target) {
  this.target = target;
 }

 public void setAdvice(Advice advice) {
  this.advice = advice;
 }

 public Object getProxyBean() {
  Class cla = Proxy.getProxyClass(target.getClass().getClassLoader(),
    target.getClass().getInterfaces());
  class MyInvocationHandler implements InvocationHandler {
   @Override
   public Object invoke(Object proxy, Method method, Object[] args)
     throws Throwable {
    Object obj = method.invoke(target, args);
    return obj;
   }
  }
  Collection obj = null;
  try {
   obj = (Collection) cla.getConstructor(InvocationHandler.class)
     .newInstance(new MyInvocationHandler());
   obj.add("dsfadf");
   System.out.println(obj.size());
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return obj;
 }
}

package org.cc.aop;

import java.io.InputStream;
import java.util.Properties;
/*
 * 生成一个代理类对象或目标类对象
 */
public class BeanFactory {
 Properties pro = new Properties();

 public BeanFactory(InputStream is) {
  try {
   pro.load(is);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public Object getBean(String name) throws Exception {
  String className = pro.getProperty(name);
  Class clazz = Class.forName(className);
  Object bean = clazz.newInstance();
  if (bean instanceof ProxyFactoryBean) {
   ProxyFactoryBean proxyBean = (ProxyFactoryBean) bean;
   Object target = Class.forName(pro.getProperty(name + ".target"))
     .newInstance();
   Advice advice = (Advice) Class.forName(
     pro.getProperty(name + ".advice")).newInstance();
   proxyBean.setTarget(target);
   proxyBean.setAdvice(advice);
   Object obj = proxyBean.getProxyBean();
   return obj;
  }
  return bean;
 }
}

package org.cc.aop;

import java.lang.reflect.Method;
//定义Advice接口及其抽象方法
public interface Advice {
 void before(Method method, Object... args);

 void after(Method method, Object... args);
}

package org.cc.aop;

import java.lang.reflect.Method;
//实现自定义的Advice接口
public class MyAdvice implements Advice {
 long time = System.currentTimeMillis();

 @Override
 public void after(Method method, Object... args) {
  System.out.println(method.getName() + "...start");

 }

 @Override
 public void before(Method method, Object... args) {
  System.out.println(method.getName() + "...over");
  System.out.println(method.getName() + "...time.."
    + (System.currentTimeMillis() - time));

 }

}

source.properties文件:

#xxx=java.util.ArrayList
xxx=org.cc.aop.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=org.cc.aop.MyAdvice

package org.cc.aop;

import java.io.InputStream;
import java.util.Collection;
//动态代理测试类
public class AOPTest {
 public static void main(String[] args) throws Exception {
  InputStream is = AOPTest.class.getResourceAsStream("source.properties");
  BeanFactory bean = new BeanFactory(is);
  Object obj = bean.getBean("xxx");
  System.out.println(obj.getClass().getName());
  Collection coll = (Collection) obj;
  coll.add("fdfsf");
  coll.add("afffsdf");
  System.out.println(coll.size());
 }
}

---------------------- android培训java培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net/heima

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值