概念
Ø 要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理,日志、事务管理、等
Ø 编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码
Ø 如果采用工程模式和配置文件的方法进行管理,则不需要修改客户端程序,在配置文件中配置使用目标类还是代理类,这样很容易切换,
生成代理类
方法一:
InvocationHandler handler = new MyInvocationHandler(...);
//得到代理类的字节码对象
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });
//先得到 该字节码的构造函数,然后通过构造函数 实例化一个对象
Foo f = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });
方法二:通过Proxy.newProxyInstance() 静态方法
Foo f = (Foo) Proxy.newProxyInstance(
Foo.class.getClassLoader(),//类加载器
new Class[] { Foo.class },//接口的字节码对象
handler);//必要的 参数
综合上面的可以生成一个万能的接口代理方法
private static Object getProxy(final Object target , final Advice advice) {
Object proxy= Proxy.newProxyInstance(
target.getClass().getClassLoader(),//参数一目标对象(一般都是接口的实现类)
/*new Class[]{Collection.class}*/
target.getClass().getInterfaces(), //参数二: 目标对象的接口
new InvocationHandler() {//参数三
/**
* proxyCol.add("adf"); 以此为例
* @proxy代理对象 proxyCol
* @method 代理对象调用的方法
* @args代理对象调用的方法,传递的参数
*/
@Override
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;
}
Collection arr = new ArrayList();
Collection proxyCol = (Collection)getProxy(arr,new MyAdvice());
proxyCol.add("adf");
需要注意的地方:
System.out.println(proxyCol.getClass().getName());//得到的结果是$Proxy1 或者类似这样的,反正不算目标类(Collection ),原因如下:
getClass()方法是从Object对象上继承过来的,hashCode、equals 或 toString 也都是从Object类中继承来的,但只有这三个方法交给了Handler去处理,其他的方法都不交给Handler处理。
public class BeanFactory {
Properties props = new Properties();
/**
* 加载配置文件信息
* @param in
*/
public BeanFactory(InputStream in){
try {
props.load(in);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Object getBean(String name){
Object bean = null;
try {
String className = props.getProperty(name);
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 proxy = (ProxyFactoryBean)bean;
try {
Advice advice = (Advice)(Class.forName(props.getProperty(name+".advice")).newInstance());
Object target= (Object)(Class.forName(props.getProperty(name+".target")).newInstance());
proxy.setAdvice(advice);
proxy.setTarget(target);
bean= proxy.getProxy();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return bean;
}
}
public class ProxyFactoryBean {
private Object target;
private Advice advice;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getProxy() {
Object proxy= Proxy.newProxyInstance(
target.getClass().getClassLoader(),//目标对象(一般都是接口的实现类)
/*new Class[]{Collection.class}*/
target.getClass().getInterfaces(), //目标对象的接口
new InvocationHandler() {
/**
* proxyCol.add("adf"); 以此为例
* @proxy 代理对象 proxyCol
* @method 代理对象调用的方法
* @args 代理对象调用的方法,传递的参数
*/
@Override
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;
}
}
AopFrameworkTest类
public class AopFrameworkTest {
public static void main(String[] args) {
testMyAopFramework();
}
public static void testMyAopFramework(){
try {
InputStream in = AopFrameworkTest.class.getResourceAsStream("conf.properties");
BeanFactory beanFac = new BeanFactory(in);
Object obj =beanFac.getBean("xxx");
System.out.println(obj.getClass().getName());//打印类名称
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}