2018-01-31

spring aop

@(iJava)[spring framework]

[toc]


aop底层原理
采用动态代理设计模式面向对象思想的为每个方法添加预热方法和擦屁股方法:-),

  • 动态代理:只需要把对象(类)交给第三方管理,至于怎么管理就不需要我们操心了
    一个标准的xml
  • 用最懒的办法为每个核心业务逻辑添加非核心组成部分(事务 日志 权限 异常 测试运行时间)去除以前的代码种session.beginTransaction();等冗余代码
public class Test {
    public static void main(String[] args) {
        //System.getProperties().put("sun.misc.ProxyG", arg1)
        jdkProxy();
    }   
    public static void jdkProxy(){
        JdkProxy proxy = new JdkProxy();
        IUser user = (IUser)proxy.bind(new User());
        //jdk版本底层是proxy 间接implements IUser,可以强转(但没有继承User)
        String result = user.add("1", "zhangsan");
        System.out.println("result:"+result);
    }
    public static void cglibProxy(){
        CglibProxy proxy = new CglibProxy();
        IUser user = (User)proxy.bind(new User());
        String result = user.add("etoak", "et1710");
        System.out.println("返回结果:"+result);
    }
}
为了实现添头加尾,那么首先需要得到这个方法
public class JdkProxy {
    public Object bind(final Object target) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), 
                new InvocationHandler() {
                //指明生成代理对象使用哪个类装载器,得到要处理的数据
                //指明生成哪个对象的代理对象,通过接口指定
                //类将代理实例传递给内部类,指明产生的这个代理对象要做什么事情
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
                    //拿到类装载器提供的数据,组装一个target.getClass().getInterfaces()的实现类
                        start();
                        //核心业务逻辑
                        Object result = method.invoke(target, args);
                        end();
                        return result;
                    }
                });
    }       
}
public class CglibProxy implements MethodInterceptor{
    public Object bind(Object target){
        Enhancer e = new Enhancer();
        e.setSuperclass(target.getClass());
        e.setCallback(this);
        return e.create();
    }
    @Override
    public Object intercept(Object object, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        start();
        Object result = proxy.invokeSuper(object, args);
        end();
        return result;
    }
}
public interface IUser {
    public String add(String id,String name);
}
public class User implements IUser {
    @Override
    public String add(String id, String name) {
        System.out.println("ID:"+id);
        System.out.println("Name:"+name);
        return id+"|"+name;
    }
}

xml配置方法

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
  • <aop:config>...</aop:config>
    • <aop:pointcut expression="execution(* com.etoak.controller.*.*(..))" id="p" />
    • <bean id="login" class="com.etoak.controller.LoginController" />
  • ==设置动态代理模式==<aop:aspectj-autoproxy proxy-target-class="true"/>
    • false:先找jdk代理,没有找到jdk代理使用cglib
    • true: 强制使用cglib代理
    • 设置true减少判断,提高性能

切入点表达式
* com.etoak.controller.LoginController.login(..)

execution(* com.etoak.controller..add(..))
and execution(
com.etoak.controller.*.del(..))

execution(* com.etoak.controller..add(..))
|| execution(
com.etoak.controller.*.del(..))

  • 第一个*表示方法返回值 返回值可有可无
  • 第二个*表示所有的的类
  • 第三个*表示所有的方法
  • (..)表示方法参数 参数可有可无
  • com.etoak.controller 包结构

aop注解

注解原理首先反射加载类(方法),然后捕获注解,如果存在切面注解,那么继续...

  • @Aspect
    ==实现aop注解必须注解为切面类==,相当于xml中的容器:<aop:config></aop:config>切面类相当于一个容器,里面装的方法相当于aop的切入点,连接点和通知
  • @Pointcut("execution(* com.etoak.controller.*.*(..))")
    • 相当于<aop:pointcut expression="execution(* com.etoak.controller.*.*(..))" id="p" />因为本身在一个类体里面,所以id也就不重要了(this)
    • 方法的书写规范:无参 无返回值 任意命名public void任意名称(){}
  • @Before("切入点方法名")
    • 标签对应方法:public void任意(JoinPoint jp){方法体}
    • 相当于<aop:before advice-ref="beforeAdvice" pointcut-ref="p" />+如下demo:标签并没有判断该类是before,after,around或者afterThrowing,是通过实现的接口来判断的
public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object object)throws Throwable {

    }   
}

  • @AfterReturning(value="切入点方法名",returning="result")
    • 标签对应方法:public void任意(JoinPoint jp,Object result){方法体}
      • 需要注意参数的顺序
      • returning="result" is Object result,反射加载方法,然后用方法的参数对应寻找注解的参数
      • 关于JoinPoint
    • 相当于<aop:before advice-ref="" pointcut-ref="" />+如下demo:
public class AfterAdvice implements AfterReturningAdvice{
    @Override
    public void afterReturning(Object result, Method method, Object[] args,Object object) throws Throwable {

    }   
}

  • @Around(value="etoak()")
    • 相当于xml标签 + 实现MethodInterceptor接口
    • 参数为ProceedingJoinPoint
    @Around(value="etoak()")
    public Object around(ProceedingJoinPoint pjp)throws Throwable{
        start();//before()
        Object result = pjp.proceed();
        end();//after()
        return result;
    }

xml标签 + 实现MethodInterceptor接口

public class AroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable{
        Object object = invocation.getThis();
        Method method = invocation.getMethod();
        Object[] args = invocation.getArguments();

        System.out.println(object.getClass().getName());
        start();
        Object result = invocation.proceed();
        end();
        return result;
    }

    public void start() {
        //
    }

    public void end() {
        //
    }

}

  • @AfterThrowing(value="etoak()",throwing="e")
    • 相当于标签 + implements ThrowsAdvice
      • ThrowsAdvice提供了4种方法提供重写,因为是4选一,所以接口没有提供任何方法,提供就得同时重写4种方法,只是在文档进行了说明

Tag interface for throws advice.
There are not any methods on this interface, as methods are invoked by reflection. Implementing classes must implement methods of the form:
void afterThrowing([Method, args, target], ThrowableSubclass);Some examples of valid methods would be:
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
The first three arguments are optional, and only useful if we want further information about the joinpoint, as in AspectJ after-throwing advice.

注解版:同时实现了打印日志功能

    @AfterThrowing(value="etoak()",throwing="e")
    public void ex(JoinPoint jp,Exception e){
        try (OutputStream os = new FileOutputStream("C:/1.txt",true);
                PrintWriter out = new PrintWriter(os)) {
            e.printStackTrace(out);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

标签版:

public class ThrowAdvice implements ThrowsAdvice {
    public void afterThrowing(Method method, Object[] args, Object target,Exception ex) {
        System.out.println("目标对象:" + target.getClass().getName());
        System.out.println("目标对象方法:" + method.getName());
        System.out.println(args);
        System.out.println(ex.getMessage());
        try (OutputStream os = new FileOutputStream("C:/1.txt",true);
                PrintWriter out = new PrintWriter(os)) {
            ex.printStackTrace(out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

参考文档:
https://www.cnblogs.com/xdp-gacl/p/3971367.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容