美文网首页
2018-01-31

2018-01-31

作者: zigzh | 来源:发表于2018-01-31 23:22 被阅读0次

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

相关文章

网友评论

      本文标题:2018-01-31

      本文链接:https://www.haomeiwen.com/subject/ierrzxtx.html