Spring-aspectJ

1. 介绍

通过aspectJ,使用aspectJ,就不用像之前一样,切面类需要继承一些切面父类了,可以随意自定义一个切面类,然后配置一下就可以了,可以通过配置的方式,也可以通过注解的方式

 

2. xml配置方式

实现类

package com.test.spring.aspectJ;

public class UserServiceImpl implements UserService{

    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
        
    }

    public void editUser() {
        System.out.println("修改用户");
        
    }

}

 

切面类

public class MyAspect {
    
    public void monitorBefore() {
        System.out.println("执行前");
    }
}

 

xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<beans   xmlns="http://www.springframework.org/schema/beans" 
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/context
                              http://www.springframework.org/schema/context/spring-context.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
        
        <!-- 实现类 -->
        <bean id="userService" class="com.test.spring.aspectJ.UserServiceImpl"></bean>
        
     <!-- 切面类 -->
        <bean id="myAspect" class="com.test.spring.aspectJ.MyAspect"></bean>
        <aop:config>
       <!-- 切面配置 ref 对应面类-->
            <aop:aspect ref="myAspect" >
          <!-- 切入点,
              expression对应执行方法的公式,这个公式很好理解,声明类型 返回值 包名.类名.方法名(参数类型) throws 抛出异常全限定名
              id 切入点ID
          -->
                <aop:pointcut expression="execution(* com.test.spring.aspectJ.UserServiceImpl.addUser())" id="addPointCut"/>
                
          <!-- aop:before就是切入的类型,这里使用before意思就是在方法之前调用,method就是切入的方法,pointcut-ref就是切入点ID,
              这里还可以自定义表达式,pointcut就是自己重新定义切入点表达式,这里使用pointcut或者pointcut-ref都可以 -->
          <aop:before method="monitorBefore" pointcut-ref="addPointCut"/> </aop:aspect> </aop:config> </beans>

 

运行测试类

package com.test.spring.aspectJ;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAspectJ {

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("/com/test/spring/aspectJ/springConfig.xml");
    
        UserService userservice = context.getBean("userService",UserService.class);
    
        userservice.addUser();
        userservice.deleteUser();
        userservice.editUser();
        
    }
}

 

运行结果,可以看出,切面先执行切面方法在执行目标方法,并且可以看出,因为表达式中只对addUser的方法进行切入,所以只要在添加用户前才进行切入

执行前
添加用户
删除用户
修改用户

 

这里我们注意的是所有的切入类型,如aop:before 或者aop:after,都可以没有入参,或者有一个或以上的参数,默认第一个参数为 Joinpoint, 这个对象里面包含了很多切入点的信息,包括切入的方法名,类名,等等的一些信息

 

3.不同切入类型配置和切入类的写法

  • aop:before
<aop:before method="monitorBefore" pointcut-ref="addPointCut"/>

 

切面类方法

public void monitorBefore(JoinPoint joinPoint) {
        System.out.println("执行前");
    }

 

  • aop:after-returning

这里的return等于切入方法monitorAfter入参中,第二个参数名,用于告诉切入方法返回的值是什么

<aop:after-returning method="afterReturning" pointcut-ref="addPointCut" returning="ret"/>

 

切面类方法

/**
     * 参数1 连接点的描述,包括目标函数的名称,字段
     * 参数2 类型Object,需要在配置指定名称 与这里的名称一致
     * @param joinPoint
     * @param ret
     */
    public void afterReturning(JoinPoint joinPoint, Object ret) {
        System.out.println("After Returning");
    }

 

  • aop:around
<aop:around method="myAround" pointcut-ref="addPointCut"/>

 

切面类方法,这里必须手动调用目标方法

/**
     * 环绕
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("前");
        Object obj = joinPoint.proceed();
        System.out.println("后");
        return obj;
    }

 

  • aop:after-throwing

这里的throwing等于入参中的第二个方法,告诉切入点,异常的对象,当目标切入点方法执行并抛出异常,机会进入到这个切面类型当中

<aop:after-throwing method="myThrow" pointcut-ref="addPointCut" throwing="e"/>

 

切面类方法

public void myThrow(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常了");
    }

 

  • aop:after
<aop:after method="monitorAfter" pointcut-ref="addPointCut"/>

 

切面类方法

/**
     * 
     * @param joinPoint 目标函数
     */
    public void monitorAfter(JoinPoint joinPoint) {
        
        System.out.println("执行后");
    }

 

3.基于注解

基于下面的xml配置,把它转化成注解的方式

<?xml version="1.0" encoding="UTF-8" ?>
<beans   xmlns="http://www.springframework.org/schema/beans" 
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/context
                              http://www.springframework.org/schema/context/spring-context.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
        
        
        <bean id="userService" class="com.test.spring.aspectJ.UserServiceImpl"></bean>
        
        <bean id="myAspect" class="com.test.spring.aspectJ.MyAspect"></bean>
        
        <aop:config>
            <aop:aspect ref="myAspect" >
                <aop:pointcut expression="execution(* com.test.spring.aspectJ.UserServiceImpl.addUser())" id="addPointCut"/>
                <aop:before method="monitorBefore" pointcut-ref="addPointCut"/>
                <aop:after-returning method="monitorAfter" pointcut-ref="addPointCut" returning="ret"/>
                <aop:around method="myAround" pointcut-ref="addPointCut"/>
                <aop:after-throwing method="myThrow" pointcut-ref="addPointCut" throwing="e"/>
                <aop:after method="myThrow" pointcut-ref="addPointCut"/>
            </aop:aspect>
            
        </aop:config>
     
</beans>

 

这里分几个步骤

  • xml配置中,把所有的内容都去掉,只剩下组件扫描和aspectJ自定代理配置
<?xml version="1.0" encoding="UTF-8" ?>
<beans   xmlns="http://www.springframework.org/schema/beans" 
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/context
                              http://www.springframework.org/schema/context/spring-context.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
        
        <context:component-scan base-package="com.test.spring.aspectJ.anno"></context:component-scan>
        
       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
     
</beans>

 

  • 在应用的bean中添加组件注解和切面类中添加注解

实现类声明是bean

package com.test.spring.aspectJ.anno;

import org.springframework.stereotype.Component;

@Component("UserServiceImpl")
public class UserServiceImpl implements UserService{

    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
        
    }

    public void editUser() {
        System.out.println("修改用户");
        
    }

}

 

切面类

package com.test.spring.aspectJ.anno;

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.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {
    
}

 

  • 切面类方法添加注解

这里注意的是,我们可以在注解当中,假如只有一个属性,我们可以省略value=,假如是两个属性,必须有value值,表达式也可以写一个公共类,value只要指定对应的方法名即可

声明公共表达式的方式,调用的时候,还需要@Before(value="pointCut()")即可,或者不用value, @Before("pointCut()")

@Pointcut("execution(* com.test.spring.aspectJ.anno.UserServiceImpl.deleteUser())")
    private void pointCut() {
    }

 

@Before

@Before("execution(* com.test.spring.aspectJ.anno.UserServiceImpl.deleteUser())")
    public void monitorBefore(JoinPoint joinPoint) {
        System.out.println("执行前");
    }

 

@AfterReturning

@AfterReturning(value="pointCut()",returning="ret")
    public void afterReturning(JoinPoint joinPoint, Object myReturn) {
        System.out.println("After Returning");
    }

 

@Around

@Around(value="pointCut()")
    public Object myRound(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("前");
        Object obj = joinPoint.proceed();
        System.out.println("后");
        return obj;
    }

 

@AfterThrowing

@AfterThrowing(value="pointCut()",throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常了");
    }

 

@After

@After(value="pointCut()")
    public void monitorAfter(JoinPoint joinPoint) {
        
        System.out.println("执行后");
    }

 

posted @ 2019-06-01 14:23  长命百岁  阅读(440)  评论(0编辑  收藏  举报