让动态生成的类成为目标类的代理-实现AOP功能的封装与配置

让动态生成的类成为目标类的代理
·分析动态代理的工作原理图


·怎样将目标类传递进去?
 -直接在InvocationHandler实现类中创建目标类的实例对象,可以看运行效果和加入日志代码,但没有实际意义。
 -为InvocationHandler实现类注入目标类的实例对象,不能采用匿名内部类的形式了。
 -让匿名的InvocationHandler实现类访问外面方法中的目标类实例对象的final类型的引用变量。
·将创建代理的过程改为一种更优雅的方式,eclipse重构出一个getProxy方法绑定接收目标同时返回代理对象,让调用者更懒惰,更方便,调用者甚至不用接触任何代理的API。
·将系统功能代码模块化,即将切面代码也改为通过参数形式提供,怎样把要执行的系统功能代码以参数形式提供?
 -把要执行的代码装到一个对象的某个方法里,然后把这个对象作为参数传递,接收者只要调用这个对象的方法,即等于执行类外界 提供的代码!
 -为bind方法增加Advice参数。
以上编程代码:
package lqq.heima.day3;

import java.lang.reflect.Method;

public interface Advice {
 
 void beforeMethod(Method method);
 void afterMethod(Method method);

}
package lqq.heima.day3;

import java.lang.reflect.Method;

public class MyAdvice implements Advice {

 long beginTime = 0;
 @Override
 public void afterMethod(Method method) {
  // TODO Auto-generated method stub
  System.out.println("张孝祥Java高新技术学习完成了");
  long endTime = System.currentTimeMillis();
  System.out.println(method.getName()+" 方法调用共耗时:" +(endTime -beginTime)+" 毫秒");


 }

 @Override
 public void beforeMethod(Method method) {
  // TODO Auto-generated method stub
  System.out.println("张孝祥Java高新技术学习开始了");
  beginTime = System.currentTimeMillis();

 }

}
package lqq.heima.day3;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyTest2 {

 /**
  * @param args
  */
 @SuppressWarnings("unchecked")
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  final ArrayList target = new ArrayList();
  Collection proxy2 = (Collection) getProxy(target,new MyAdvice());
  proxy2.add("zxx");
  proxy2.add("lhm");
  proxy2.add("bxd");
  System.out.println(proxy2.size());
 }

 private static Object getProxy(final Object target, final Advice advice) {
  Object proxy2 = Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    /*new Class[]{Collection.class},*/
    target.getClass().getInterfaces(),
    new InvocationHandler(){
     

     @Override
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {
      // TODO Auto-generated method stub
      
      /*long beginTime = System.currentTimeMillis();
      Object  retVal = method.invoke(target, args);
      long endTime = System.currentTimeMillis();
      System.out.println(method.getName()+" 方法调用共耗时:" +(endTime -beginTime)+" 毫秒");
      return retVal;*/
      //return method.invoke(proxy, args);/*此处如果这样返回调用会形成死循环:我们的类中调用了代理的方法,代理的方法将调用该代理的代理对象、方法名称、和方法的参数传递给类了handler的invoke方法,我们又再handler的invoke方法中调用method的invoke方法将目标回设置成代理对象,造成死循环*/
      
      advice.beforeMethod(method);
      Object  retVal = method.invoke(target, args);
      advice.afterMethod(method);
      return retVal;
      
     }
     
    });
  return proxy2;
 }

}


实现AOP功能的封装与配置

·工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象。
·BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:
#xxx=java.util.ArrayList
xxx=lqq.heima.day3.aopframework.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=lqq.heima.day3.MyAdvice
·ProxyFactoryBean充当封装生成动态代理的工厂,需要为工厂类提供哪些配置参数信息?
 -目标
 -通知
·编写客户端应用:
 -编写实现Advice接口的类和在配置文件中进行配置
 -调用BeanFactory获取对象。
package lqq.heima.day3;

import java.lang.reflect.Method;

public interface Advice {
 
 void beforeMethod(Method method);
 void afterMethod(Method method);

}
package lqq.heima.day3;

import java.lang.reflect.Method;

public class MyAdvice implements Advice {

 long beginTime = 0;
 @Override
 public void afterMethod(Method method) {
  // TODO Auto-generated method stub
  System.out.println("张孝祥Java高新技术学习完成了");
  long endTime = System.currentTimeMillis();
  System.out.println(method.getName()+" 方法调用共耗时:" +(endTime -beginTime)+" 毫秒");


 }

 @Override
 public void beforeMethod(Method method) {
  // TODO Auto-generated method stub
  System.out.println("张孝祥Java高新技术学习开始了");
  beginTime = System.currentTimeMillis();

 }

}
package lqq.heima.day3.aopframework;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import lqq.heima.day3.Advice;

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() {
  // TODO Auto-generated method stub
  Object proxy2 = Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    /*new Class[]{Collection.class},*/
    target.getClass().getInterfaces(),
    new InvocationHandler(){
     

     @Override
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {
      // TODO Auto-generated method stub
      
      /*long beginTime = System.currentTimeMillis();
      Object  retVal = method.invoke(target, args);
      long endTime = System.currentTimeMillis();
      System.out.println(method.getName()+" 方法调用共耗时:" +(endTime -beginTime)+" 毫秒");
      return retVal;*/
      //return method.invoke(proxy, args);/*此处如果这样返回调用会形成死循环:我们的类中调用了代理的方法,代理的方法将调用该代理的代理对象、方法名称、和方法的参数传递给类了handler的invoke方法,我们又再handler的invoke方法中调用method的invoke方法将目标回设置成代理对象,造成死循环*/
      
      advice.beforeMethod(method);
      Object  retVal = method.invoke(target, args);
      advice.afterMethod(method);
      return retVal;
      
     }
     
    });
  return proxy2;
 }

}
package lqq.heima.day3.aopframework;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import lqq.heima.day3.Advice;

public class BeanFactory {
 Properties props = new Properties();
 public BeanFactory(InputStream ips){
  try {
   props.load(ips);
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
 }
 
 @SuppressWarnings("unchecked")
 public Object getBean(String name){
  Object bean =null;
  String className = props.getProperty(name);
  try {
   Class clazz = Class.forName(className);
   bean = clazz.newInstance();
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InstantiationException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  if(bean instanceof ProxyFactoryBean){
   ProxyFactoryBean proxyFactoryBean =(ProxyFactoryBean)bean;
   Object proxy = null;
   try {
    Advice advice = (Advice) Class.forName(props.getProperty(name+".advice")).newInstance();
    Object target = Class.forName(props.getProperty(name+".target")).newInstance();
    proxyFactoryBean.setAdvice(advice);
    proxyFactoryBean.setTarget(target);
   } catch (InstantiationException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IllegalAccessException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   proxy = (proxyFactoryBean).getProxy();
   return proxy;
  }
  return bean;
 }

}
下面是config.properties配置文件的内容:
#package lqq.heima.day3.aopframework;
xxx=java.util.ArrayList
#xxx=lqq.heima.day3.aopframework.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=lqq.heima.day3.MyAdvice
package lqq.heima.day3.aopframework;

import java.io.InputStream;
import java.util.Collection;

public class AopFrameworkTest {

 /**
  * @param args
  */
 @SuppressWarnings("unchecked")
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
  Object bean = new BeanFactory(ips).getBean("xxx");
  System.out.println(bean.getClass().getName());
  Collection col = (Collection) bean;
  col.add("123");
  System.out.println("col.size() is:"+col.size());
  

 }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值