让动态生成的类成为目标类的代理·分析动态代理的工作原理图
·怎样将目标类传递进去? -直接在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.ArrayListxxx=lqq.heima.day3.aopframework.ProxyFactoryBeanxxx.target=java.util.ArrayListxxx.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.ProxyFactoryBeanxxx.target=java.util.ArrayListxxx.advice=lqq.heima.day3.MyAdvicepackage 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());
}
}