黑马程序员-java-代理

---------------------- android培训java培训、期待与您交流! ----------------------
 代理,从字面意思理解,就是要去做一件事,不直接去做,去找中介帮你完成,那中介就算是代理吧。
java语言有静态代理和动态代理,静态代理一个真实角色必须对应一个代理角色,真实角色必须是事先
已经存在的,并作为代理对象的内部属性。看下面实例:
public abstract class Subject
{
 public abstract void request();
}
public class RealSubject extends Subject
{
 public void request()
 {
  System.out.println("From real subject.");
 }
}
public class ProxySubject extends Subject
{
 private RealSubject realSubject;
 
 public void request()
 {
  this.preRequest(); //在真实角色操作之前所附加的操作
  
  if(null == realSubject)
  {
   realSubject = new RealSubject();
  }
  
  realSubject.request(); //真实角色所完成的事情
  
  this.postRequest(); //在真实角色操作之后所附加的操作
 }
 
 private void preRequest()
 {
  System.out.println("before request");
 }
 
 private void postRequest()
 {
  System.out.println("after request");
 }
}
public class Client
{
 public static void main(String[] args)
 {
  Subject subject = new ProxySubject();
  
  subject.request();
 }
}
以上程序中,真实角色RealSubject实现Subject接口,代理角色ProxySubject内部含有RealSubject,代理角色内部
实现subject.request(),其实是真实角色realSubject.request(),这就是静态代理模型。
由于静态代理要求真实角色必须事先存在,所以大量使用会导致类的急剧膨胀,就引出了java的动态代理。

 java动态代理基于反射实现,是在运行时刻生成的class,假如有一个类A,它实现了interface1和interface2接口,动态代理
 就是在运行时刻提供interface1和interface2两个接口给它,它生成一个B对象,该对象宣称实现了interface1,interface2两
 个接口,当然你可以把B对象当作interface1和interface2的任何一个来用(父类引用指向子类对象),而实际中你调用B对象完成
 的功能都是由A对象来完成的,B对象是A对象实例的代理。

代理实例生成方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
第一个参数为类加载器,就调用真实角色的加载器就可以了(如上面的A),第二个参数为代理实例宣称实现的真实角色所
实现的接口的class类型的数组,第三个参数是一个实现了InvocationHandler接口的类。

InvocationHandler接口里面有个invoke方法,真实角色通过实现invoke方法,完成代理的操作,如下:
public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable
 {
  return method.invoke(target, args);
 }
反射method对象对应代理角色所调用的方法,target为调用的真实角色的引用。

下面方法返回任意一个对象的代理实例:
public Object getProxy()
 {
     Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
    new InvocationHandler()
    {
     @Override
     public Object invoke(Object proxy, Method method,Object[] args) throws Throwable
     {
            Object obj = method.invoke(target, args);
       return obj;
     }
    });

  return proxy;
 }

看下面的应用:
public interface Foo
{
 void doAction();
}
public class FooImpl implements Foo
{
 public void doAction()
 {
  System.out.println("in FooImpl doAction!");
 }
}
public class CommonInvocationHandler implements InvocationHandler
{
 private Object target;
 public CommonInvocationHandler(Object target)
 {
  this.target = target;
 }
 public CommonInvocationHandler()
 {}
 public void setTarget(Object target)
 {
  this.target = target;
 }
  public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable
 {
  return method.invoke(target, args);
 }
}
public class Demo
{
 public static void main(String[] args)
 {
  CommonInvocationHandler handler = new CommonInvocationHandler();
  Foo f = null;
  handler.setTarget(new FooImpl());
  f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
    new Class[] { Foo.class }, handler);
  System.out.println(f.getClass().getName());
  f.doAction();

 }
}
程序输出:$Proxy0
in FooImpl doAction!

FooImpl实现接口Foo,System.out.println("in FooImpl doAction!"),
newProxyInstance方法的handler参数,传入的是真实角色new FooImpl(),
通过handler.setTarget(new FooImpl())把invoke方法中的target设置为new FooImpl(),
Proxy.newProxyInstance产生实例f,f.doAction()方法,实际执行new FooImpl().doAction,
f只是FooImpl实例的一个代理,所以f.getClass().getName()打印$Proxy0。


下面用动态代理实现类似spring的可配置的AOP框架,代码如下:
public class BeanFactory
{
 Properties prop = new Properties();
  public BeanFactory(InputStream ips)
 {
  try
  {
   prop.load(ips);
  }
  catch (IOException e)
  {

   e.printStackTrace();
  }
 }
 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();
  }

  if (bean instanceof ProxyFactoryBean)
  {
   Object proxy = null;
   ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean;
   try
   {
    Advice advice = (Advice) Class.forName(
      prop.getProperty(name + ".advice")).newInstance();
    Object target = Class.forName(
      prop.getProperty(name + ".target")).newInstance();
    proxyFactoryBean.setAdvice(advice);
    proxyFactoryBean.setTarget(target);
    proxy = proxyFactoryBean.getProxy();
   }
   catch (Exception e)
   {

    e.printStackTrace();
   }

   return proxy;
  }

  return bean;
 }
}
//Bean工厂用于从配置文件config.properties中读取信息,如果配置文件key的值为给定真实目标类的全名,
就返回该类的一个实例,如果配置文件key的值为ProxyFactoryBean,就返回目标类的一个代理实例。

public class ProxyFactoryBean
{
 private Advice advice;
 private Object target;
  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 Object getProxy()
 {
    Object proxy3 = Proxy.newProxyInstance(target.getClass()
    .getClassLoader(), target.getClass().getInterfaces(),
    new InvocationHandler()
    {
     @Override
     public Object invoke(Object proxy, Method method,
       Object[] args) throws Throwable
     {

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

      return obj;
     }
    });
     return proxy3;
 }
}
//代理Bean工厂ProxyFactoryBean,用于生产目标类的一个代理实例,在目标执行系统操作的前后,
还可以加上附带的功能advice.beforeMethod(method)和 advice.afterMethod(method)。我们要做的
就是编写Myadvice类,实现附加功能接口Advice.

public class AopFrameworkTest
{
  public static void main(String[] args)
{
 InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
 
 Object bean = new BeanFactory(ips).getBean("xxx");
 
 System.out.println(bean.getClass().getName());
}
}
当配置文件内容为:
xxx=java.util.ArrayList
#xxx=com.aopframework.ProxyFactoryBean
xxx.advice=com.daili.MyAdvice
xxx.target=java.util.ArrayList
程序打印java.util.ArrayList,bean为目标类的一个实例

当配置文件内容为:
#xxx=java.util.ArrayList
xxx=com.aopframework.ProxyFactoryBean
xxx.advice=com.daili.MyAdvice
xxx.target=java.util.ArrayList
程序打印$Proxy0,bean为目标代理类的一个实例。

 

 


 

---------------------- android培训java培训、期待与您交流! ----------------------详细请查看: http://edu.csdn.net/heima
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值