aop之动态代理

前言

Spring的两大特征,一个是IOC,一个是AOP。前者是控制反转,主要的思想是依赖注入,在action层我们需要service层对象,在service层我们需要dao层对象,通过Spring通过IOC技术自动我们注入对象。AOP的主要思想是在执行业务逻辑的前后,我们需要执行一些逻辑,比如日志,事务等,通过动态代理就可以完美解决这些需求。本次着重讲一下AOP。

AOP实现

注解相关
代理相关注解
/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface proxu {
    //目标执行之前需要执行到的类
    Class[] aopbefore();
    //目标执行之后需要执行到的类
    Class[] aopafter();
    //需要代理的接口
    Class[] interfaces();
}
动作相关注解
目标执行之前注解标记
/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface doBefore {

}
目标执行之后注解标记
/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface doAfter {
}
目标接口
目标接口可以有多个,下面列出两个目标接口
package com.yzz.java.proxyer;

/**
 * Created by yzz on 2017/8/13.
 */
public interface IProxy {
    void method1();
    String method2();
    String method3(String arg);
}
package com.yzz.java.proxyer;

/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */

public interface IProxy2 {
    void methodIProxy2();
}
对应的动作类,可以有多个,我这里就列出两个doAfter标记的,dobefore标记的大同小异
/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */

public class After1 {
    @doAfter
    public void dobefore1(){
        Log.e("After1===bobefore1====");
    }
    @doAfter
    public void dobefore2(){
        Log.e("After1===bobefore2====");
    }
}
/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */

public class After2 {
    @doAfter
    public void dobefore1(){
        Log.e("After2===bobefore1====");
    }
    @doAfter
    public void dobefore2(){
        Log.e("After2===bobefore2====");
    }
}
目标类
目标类可以实现多个目标接口
interfaces 参数其实也可以不写,通过反射可以动态获取所有的接口,但是不人性化,无法控制目标接口的数量
/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */
@proxu(
        aopafter = {After1.class,After2.class},
        aopbefore = {Before1.class,Before2.class},
        interfaces = {IProxy.class,IProxy2.class}
        )
public class TargetProxy implements IProxy ,IProxy2{

    @Override
    public void method1() {
        Log.e("TargetProxy:method1");
    }

    @Override
    public String method2() {
        Log.e("TargetProxy:method2");
        return "TargetProxy";
    }

    @Override
    public String method3(String arg) {
        Log.e("TargetProxy:method3");
        return arg;
    }

    @Override
    public void methodIProxy2() {
        Log.e("TargetProxy:methodIProxy2");
    }
}
proxy工具类
目标类可以实现多个目标接口
MethodInvokeBean该bean的存在是因为method的invok需要该类的实例,所以该bean就将会装载一个实例和一个方法实例。
package com.yzz.java.proxyer;

import com.yzz.java.Log;
import com.yzz.java.proxy.*;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */

public class ProxyUtils {

    public static <T> T  doProxy(T t) throws Exception{
        boolean isproxu = t.getClass().isAnnotationPresent(proxu.class);
        if (!isproxu)return t;
        proxu proxu =  t.getClass().getAnnotation(proxu.class);
        Class[] interfaces = proxu.interfaces();
        Class[] aopafter = proxu.aopafter();
        Class[] aopbefore = proxu.aopbefore();
        return (T) Proxy.newProxyInstance(
                t.getClass().getClassLoader(),
                interfaces,
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //before
                        ProxyUtils.invoke(getMethod(aopbefore,doBefore.class));
                        method.invoke(t,args);
                        //after
                        ProxyUtils.invoke(getMethod(aopafter,doAfter.class));
                        return "==";
                    }
                }
        );
    }

    /**
     * 执行方法
     * @param methods
     * @throws Exception
     */
    private static void invoke(List<MethodInvokeBean> methods) throws Exception{
        for (MethodInvokeBean m:methods) {
            m.getMethod().invoke(m.getObject());
        }
    }

    /**
     * 接收执行类的集合的方法
     * @param _class
     * @param t
     * @return
     * @throws Exception
     */
    private static List<MethodInvokeBean> getMethod(Class[] _class,Class t) throws Exception{
        List<MethodInvokeBean> methods = new ArrayList<>();
        for (Class ss:_class) {
            getMethod(ss,t,methods,ss.newInstance());
        }
        return methods;
    }

    /**
     * 获取动作类中特定标记的方法
     * @param _class
     * @param t
     * @param methods
     * @param object
     */
    private static void getMethod(Class _class, Class t,List<MethodInvokeBean> methods,Object object){
        Method[] m = _class.getMethods();
        for (Method mm:m) {
            if (mm.isAnnotationPresent(t)){
                methods.add(new MethodInvokeBean(object,mm));
            }
        }
    }
}
测试

这里写图片描述

这里写图片描述

/**
 * Created by yzz on 2017/8/13.
 * mail:yzzstyle@163.com
 */

public class Test {

    public static void main(String[] args){
        try {
//            IProxy2 iProxy2 = ProxyUtils.doProxy(TargetProxy.class.newInstance());
//            iProxy2.methodIProxy2();

            IProxy iProxy = ProxyUtils.doProxy(TargetProxy.class.newInstance());
            iProxy.method1();
            iProxy.method2();
            iProxy.method3("yzz");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值