SSH与SSM学习之Spring14——动态代理之自己的AOP框架
一、说明
这个我们需要实现的功能是这样的,通过配置文件配置所需要创建的对象需不需要代理,代理对象是谁,目标对象是谁。
其实就是对之前的代码再一次封装。
这里主要涉及到的类或者文件是
//通知的接口
Advice
//通知接口的一个实现类
MyAdvice
//通过配置文件创建实例对象,如果需要代理,那么创建代理对象。如果不需要,那么就创建指定的对象
BeanFactory
//创建代理
ProxyFactoryBean
//配置文件
config.properties
二、Advice接口
package com.qwm.spring2.d_myaop;
import java.lang.reflect.Method;
/**
* @author:qiwenming
* @date:2017/10/24 0024 22:20
* @description:
* 通知抽象类
*/
public abstract class Advice {
/**
* 方法调用之前(前置通知)
*/
public void before(){}
/**
* 方法调用之后(后置通知)
* 异常了不会调用
*/
void afterReturning(){}
/**
* 可以自己调用方法(环绕通知)
*/
void around(Object proxy, Method method, Object[] args){}
/**
* 异常时候调用(异常通知)
*/
void afterException(){}
/**
* 方法调用之后(后置通知)
* 异常了也会调用
*/
void after(){}
}
三、MyAdvice类
package com.qwm.spring2.d_myaop;
import java.lang.reflect.Method;
/**
* @author:qiwenming
* @date:2017/10/24 0024 22:18
* @description:
* 通知类
*/
public class MyAdvice extends Advice {
@Override
public void before() {
System.out.println("------before方法调用之前(前置通知)-----");
}
@Override
public void afterReturning() {
System.out.println("------afterReturning方法调用之后(后置通知 ,异常了不会调用)-----");
}
@Override
public void around(Object target, Method method, Object[] args) {
System.out.println("----------around(环绕通知)方法调用之前----------");
try {
method.invoke(target,args);
System.out.println("----------around(环绕通知)方法调用之后----------");
} catch (Exception e) {}
}
@Override
public void afterException() {
System.out.println("-------异常时候调用(异常通知)--------");
}
@Override
public void after() {
System.out.println("-------方法调用之后(后置通知)异常也调用---------");
}
}
四、ProxyFactoryBean类 创建代理对象
package com.qwm.spring2.d_myaop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author:qiwenming
* @date:2017/10/24 0024 23:02
* @description:
* 代理bean
*/
public class ProxyFactoryBean {
private Object target;
private Advice advice;
public Object getProxyObject(){
if(target==null){
throw new IllegalArgumentException("target can not null");
}
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
if(advice==null){//如果没有通知,那么直接调用
obj = method.invoke(target,args);
}else{
advice.before();
try {
advice.around(target, method, args);
obj = method.invoke(target, args);
advice.afterReturning();
advice.after();
}catch (Exception e){
// e.printStackTrace();
advice.after();
advice.afterException();
}
}
return obj;
}
});
}
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;
}
}
五、BeanFactory类 获取bean
package com.qwm.spring2.d_myaop;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* @author:qiwenming
* @date:2017/10/24 0024 23:01
* @description:
* Bean的工厂类
*/
public class BeanFactory {
Properties props = new Properties();
public BeanFactory(InputStream in){
try {
//加载配置文件
props.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取bean
* @param name 配置文件中的名字
* @return
*/
public Object getBean(String name){
String className = props.getProperty(name);
if(className==null||className.trim().equals("")){
throw new IllegalArgumentException(name + " not exits");
}
Object bean=null;
//通过完整类名来创建一个实例
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
if(bean instanceof ProxyFactoryBean){//如果需要代理
Object proxyBean = null;
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean;
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);
proxyBean = proxyFactoryBean.getProxyObject();
} catch (Exception e) {
e.printStackTrace();
}
return proxyBean;
}
return bean;
}
}
六、config.properties配置文件
#bean=java.util.ArrayList
bean=com.qwm.spring2.d_myaop.ProxyFactoryBean
bean.advice=com.qwm.spring2.d_myaop.MyAdvice
bean.target=java.util.ArrayList
七、测试
测试代码
package com.qwm.spring2.d_myaop;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* @author:qiwenming
* @date:2017/10/24 0024 23:34
* @description:
* 自己的Aop测试
*/
public class MyAopTest {
@Test
public void test1(){
//获取配置文件
InputStream ips = MyAopTest.class.getResourceAsStream("config.properties");
//获取到代理对象
List list = (List)new BeanFactory(ips).getBean("bean");
System.out.println(list.getClass().getName());
list.add("wiming");
}
}
结果
com.sun.proxy.$Proxy4
------before方法调用之前(前置通知)-----
----------around(环绕通知)方法调用之前----------
----------around(环绕通知)方法调用之后----------
------afterReturning方法调用之后(后置通知 ,异常了不会调用)-----
-------方法调用之后(后置通知)异常也调用---------
修改配置如下
bean=java.util.ArrayList
#bean=com.qwm.spring2.d_myaop.ProxyFactoryBean
bean.advice=com.qwm.spring2.d_myaop.MyAdvice
bean.target=java.util.ArrayList
再次运行代码,结果如下
java.util.ArrayList
八、源码
https://github.com/wimingxxx/spring01/tree/master/src/com/qwm/spring2/d_myaop