SSH与SSM学习之Spring14——动态代理之自己的AOP框架

  • SSH与SSM学习之Spring14动态代理之自己的AOP框架
    • 一说明
    • 二Advice接口
    • 三MyAdvice类
    • 四ProxyFactoryBean类 创建代理对象
    • 五BeanFactory类 获取bean
    • 六configproperties配置文件
    • 七测试
    • 八源码

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

你可能感兴趣的:(SSH与SSM学习)