Hyiki's 技术博客 Back-end Dev Engineer

AOP代理


切面

通常是一个类,里面定义切入点和通知

package biyeseason.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class loginProxy{

    public static Object proxy(Object target){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new loginProxyHandler(target));
    }

    private static class loginProxyHandler implements InvocationHandler{

        private Object target;

        public loginProxyHandler(Object target) {
            super();
            this.target = target;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //通知:doBefore()前置增强
            doBefore();
            //服务
            Object res = method.invoke(target,args);

            //通知:doAfter()后置增强
            doAfter();
            return res;
        }

        private void doAfter() {
            System.out.println("after...");
        }

        private void doBefore() {
            System.out.println("before...");
        }
    }
}

连接点

程序执行过程中明确的点,一般是方法的调用

  loginServiceImpl lSImpl = new loginServiceImpl();
        loginService lS = (loginService) loginProxy.proxy(lSImpl);
        login l = new login("17251102152","123456");
        boolean a = lS.login(l.getUsername(),l.getPassword());
        System.out.println(a);

前言

导包

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aop</artifactId>
   <version>4.3.7.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>1.6.12</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.6.12</version>
  </dependency>
  <dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
   <version>2.2</version>
  </dependency>

execution表达式

execution(* com.sample.service.impl..*.*(..))

解释如下:

符号 含义
execution() 表达式的主体
第一个*符号 表示返回值的类型任意
com.sample.service.impl AOP所切的服务的包名,即,我们的业务部分
包名后面的”..“ 表示当前包及子包
第二个*符号 表示类名,即所有类
.*(..) 表示任何方法名,括号表示参数,两个点表示任何参数类型

基本语法格式为:

execution(<修饰符模式>? <返回类型模式> <类路径匹配>? <方法名模式>(<参数模式>)<异常模式>?) 除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)

returning type pattern,name pattern, and parameters pattern是必须的. ret-type-pattern:可以为表示任何返回值,全路径的类名等. name-pattern:指定方法名,*代表所有,set*代表以set开头的所有方法. parameters pattern:指定方法参数(声明的类型),(..)代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个为String类型.

实现代码

package springMVCmybatis.com.my.aop;
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Before; 
import org.aspectj.lang.annotation.Pointcut; 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.After; 
import org.aspectj.lang.annotation.AfterReturning; 
import org.aspectj.lang.annotation.AfterThrowing; 
import org.springframework.core.annotation.Order;
@Aspect
// 切面执行顺序
@Order(3)
public class MyAopTest {
      @Pointcut("execution(* springMVCmybatis..addController.addEmp(..))") 
        private void pointCutMethod() { 
        } 
       
      @Pointcut("execution(* springMVCmybatis.com.my.aop.UserServiceImp.*(..))") 
        private void testAOP() { 
        }
      /*
       *  声明前置通知 ,JoinPont是srpring提供的静态变量,
       *  通过joinPoint参数可以获得目标方法的类名,方法参数,方法名等信息,这个参数可有可无。
       */
        
        @Before("pointCutMethod() || testAOP()") 
        public void doBefore(JoinPoint joinPoint) { 
            System.out.println("@Before:开始添加--order=3"); 
        } 
       
        //声明后置通知 ,如果result的类型与proceed执行的方法返回的参数类型不匹配那么就不会执行这个方法
        @AfterReturning(pointcut = "pointCutMethod()  || testAOP()", returning = "result") 
        public void doAfterReturning(String result) { 
            System.out.println("@AfterReturning:后置通知--order=3"); 
            System.out.println("---" + result + "---"); 
        } 
       
        //声明例外通知 
        @AfterThrowing(pointcut = "pointCutMethod() || testAOP()", throwing = "e") 
        public void doAfterThrowing(Exception e) { 
            System.out.println("@AfterThrowing:例外通知--order=3"); 
            System.out.println(e.getMessage()); 
        } 
       
        //声明最终通知 
        @After("pointCutMethod() || testAOP()") 
        public void doAfter() { 
            System.out.println("@After:最终通知--order=3"); 
        } 
      /*
       * 声明环绕通知
       * 参数必须是ProceedingJoinPoint,通过该对象的proceed()方法来执行目标函数,
       * proceed()的返回值就是环绕通知的返回值,proceedingJoinPoint是个接口,
       * implement JoinPoint,所以也可以获得目标函数的类名,方法名等参数。
       */
         
        @Around("pointCutMethod() || testAOP()") 
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 
            System.out.println("@Around:进入方法---环绕通知--order=3"); 
            Object o = pjp.proceed(); 
            System.out.println("@Around:退出方法---环绕通知--order=3"); 
            return o; 
        }
        
}

上面的例子中,定义了order=3,重新创建一个切面,定义order=6,执行的结果是:

@Around:进入方法---环绕通知--order=3
@Before:开始添加--order=3
@Around:进入方法---环绕通知--order=6
@Before:开始添加--order=6
============执行业务方法findUser,查找的用户是:张三=============
@Around:退出方法---环绕通知--order=6
@After:最终通知--order=6
@AfterReturning:后置通知--order=6
---张三---
@Around:退出方法---环绕通知--order=3
@After:最终通知--order=3
@AfterReturning:后置通知--order=3
---张三---
 
 
@Around:进入方法---环绕通知--order=3
@Before:开始添加--order=3
@Around:进入方法---环绕通知--order=6
@Before:开始添加--order=6
============执行业务方法addUser=============
@After:最终通知--order=6
@AfterThrowing:例外通知--order=6
null
@After:最终通知--order=3
@AfterThrowing:例外通知--order=3
null

Similar Posts

下一篇 log4j

Comments