------------android培训、java培训、期待与您交流!--------------
大纲:
一、代理概述
二、代理结构图
三、动态代理
四、动态创建代理对象的三种方式
五、InvocationHandler对象的运行原理
六、动态代理的工作原理图
七、经典动态代理示例
八、实现类似spring的可配置的AOP框架
一、代理概述
要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理、等等,你准备如何做?这就需要编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。 如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。
二、代理结构图
三、动态代理
2.在调用目标方法之后
3.在调用目标方法前后
第一种方式:
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
//结果是com.sun.proxy.$Proxy0,即代理类的类名
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());
System.out.println(proxy1);<div align="left"><pre name="code" class="java"> //结果:null
proxy.clear();
//执行没有返回值的方法,不会报告异常
proxy.size();
//执行有返回值的方法,会报告异常
System.out.println(proxy1);结果为null,不是proxy1对象为空,而是因为proxy1调用的toString方法返回值为空,从Object对象继承过来的方法有三个是调用的invoke方法,分别是:hashcode、equals、toString方法,由于invoke方法返回是null,所以toString返回null。proxy1.size()返回值是int类型与null不匹配,所以报告异常。
第二种方式(匿名内部类):
Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class );
Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class) ;
Collection proxy = (Collection)constructor.newInstance(new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null ;
}
});
System. out.println(proxy);
第三种方式(最常用):
Collection proxy = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler() {
ArrayList target = new ArrayList();
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target,args);
long endTime = System.currentTimeMillis();
System. out.println(method.getName() + " running out of " + (endTime - beginTime));
return retVal;
}
}
);
proxy.add("zxx");
proxy.add("lhm");
proxy.add("bxd");
System. out.println(proxy.size());
//结果:3
五、InvocationHandler对象的运行原理
$Proxy0 implements Collection
{
InvocationHandler handler;
public $Proxy0(InvocationHandler handler)
{
this.handler = handler;
}
}
2、动态类里的add方法:
Class Proxy$ {
add(Object object) {
return handler.invoke(Object proxy, Method method, Object[] args);
}
}
3、动态类里的方法调用示例:
$Proxy0 implements Collection
{
InvocationHandler handler;
public $Proxy0(InvocationHandler handler)
{
this.handler = handler;
}
//生成的Collection接口中的方法的运行原理
int size()
{
return handler.invoke(this,this.getClass().getMethod("size"),null);
}
void clear(){
handler.invoke(this,this.getClass().getMethod("clear"),null);
}
boolean add(Object obj){
handler.invoke(this,this.getClass().getMethod("add"),obj);
}
}
六、动态代理的工作原理图
七、经典动态代理示例
public interface Advice {
void beforeAdvice(Method method);
void afterAdvice(Method method);
}
public class MyAdvice implements Advice {
private long beginTime = 0;
public void afterAdvice(Method method) {
long endTime = System.currentTimeMillis();
System. out .println(method.getName() + " running out of " + (endTime - beginTime));
}
public void beforeAdvice(Method method) {
beginTime = System.currentTimeMillis();
}
}
public class ProxyTest {
public static void main(String[] args) throws Exception {
final ArrayList target = new ArrayList();
Collection collection = (Collection) getProxy(target,new MyAdvice());
collection.add("zxx" );
//结果:add running out of 0
}
public static Object getProxy(final ArrayList target,final Advice advice) {
Object proxy = Proxy. newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeAdvice(method);
Object retVal = method.invoke(target ,args);
advice.afterAdvice(method);
return retVal;
}
}
);
return proxy;
}
}
八、实现类似spring的可配置的AOP框架
#xxx=java.util.ArrayList
xxx=cn.itcast.ProxyFactoryBean
xxx.target=java.util.ArrayList
xxx.advice=cn.itcast.MyAdvice
目标
通知
编写实现Advice接口的类和在配置文件中进行配置
调用BeanFactory获取对象
package com.itheima.day3.aopframework;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.itcast.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() {
Object proxy = Proxy.newProxyInstance(target.getClass()
.getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy;
};
}
BeanFactory
package com.itheima.day3.aopframework;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import cn.itcast.day3.Advice;
public class BeanFactory {
Properties props = new Properties();
public BeanFactory(InputStream ips) {
try {
props.load(ips);
} catch (IOException e) {
e.printStackTrace();
}
}
public Object getBean(String name) {
String className = props.getProperty(name);
Object bean = null;
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
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);
proxy = proxyFactoryBean.getProxy();
} catch (Exception e) {
e.printStackTrace();
}
return proxy;
}
return bean;
}
}
AopFrameworkTest
package com.itheima.day3.aopframework;
import java.io.InputStream;
public class AopFrameworkTest {
public static void main(String[] args) throws Exception {
InputStream ips = AopFrameworkTest.class
.getResourceAsStream("config.properties");
Object bean = new BeanFactory(ips).getBean("xxx");
System.out.println(bean.getClass().getName());
}
}
config.properties
xxx= java.util.ArrayList
//结果:java.util.ArrayList
config.properties
xxx=com.itheima.day3.aopframework.ProxyFactoryBean
xxx.advice= com.itheima.day3.MyAdvice
xxx.target= java.util.ArrayList
//结果:$Proxy0