Spring初探之基于AspectJ实现AOP

前言

AspectJ是一个java实现的AOP框架,它能够对java代码进行AOP编译(一般在编译期进行),让java代码具有AspectJ的AOP功能。
AspectJ应用到java代码的过程称为织入,对于织入这个概念,可以简单理解为aspect(切面)应用到目标函数(类)的过程。
对于这个过程,一般分为动态织入和静态织入,动态织入的方式是在运行时动态将要增强的代码织入到目标类中,这样往往是通过动态代理技术完成的,如Java JDK的动态代理(Proxy,底层通过反射实现)或者CGLIB的动态代理(底层通过继承实现),Spring AOP采用的就是基于运行时增强的代理技术。
ApectJ采用的就是静态织入的方式。ApectJ主要采用的是编译期织入,在这个期间使用AspectJ的acj编译器(类似javac)把aspect类编译成class字节码后,在java目标类编译时织入,即先编译aspect类再编译目标类。
在这里插入图片描述
在Spring中使用AspectJ需要添加AspectJ的依赖包:

 <!-- 基于AspectJ的aop依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>

和动态代理的实现过程类似:

基于Xml文件实现

1、目标接口

public interface UserService {
    void query(String sql);
}

2、目标实现类

public class UserServiceImpl implements UserService{
    @Override
    public void query(String sql) {
        System.out.println(".......query........" + sql);
    }
}

3、这里和动态代理的实现差异性较大,直接写增强类,也就是普通的Java类

public class MyAdvice {
    public void before(){
        System.out.println("xml方式 装配 before .....");
    }
}

4、接着就是在Spring配置文件中配置AOP切面,将第三步创建的增强类交由Spring容器管理:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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.xsd">

    <!-- 配置目标对象 -->
    <bean id="uservice" class="com.lks.aspectJ.UserServiceImpl"></bean>
    <!--xml文件-->
    <!-- 配置通知类 -->
    <bean id="myAdvice" class="com.lks.aspectJ.MyAdvice"></bean>
    <!-- AOP配置 -->
    <aop:config>
        <!-- 配置AOP切面,切面是由通知和切入点组成的 -->
        <aop:aspect ref="myAdvice">
            <!-- before:前置通知 -->
            <!-- pointcut:编写切入点表达式 ,去定位需要切入的方法是哪个 -->
            <!-- method:增强类中的方法 -->
            <aop:pointcut id="queryPointcut" expression="execution(void com..UserServiceImpl.query(..))"></aop:pointcut>
            <aop:before method="before"
                        pointcut-ref="queryPointcut"
            />
        </aop:aspect>
    </aop:config>
</beans>

其中< aop:aspect >标签中的ref要与配置通知类的id一致,pointcut-ref指向 < aop:pointcut >中的id。需要注意的是切入点表达式的格式:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
execution:必须要
修饰符:可省略
返回值类型:必须要,但是可以使用通配符
包名:多级包之间使用.分割,包名可以使用
代替,多级包名可以使用多个代替, 如果想省略中间的包名可以使用 . .
类名:可以使用
代替,也可以写成ServiceImpl
方法名:也可以使用
好代替,也可以写成add*
参数:参数使用*代替,如果有多个参数,可以使用 . .代替
5、测试方法就和普通的bean调用一样,但实现了增强功能

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-aspectJ.xml")
public class TestAspectJ {

    @Autowired
    private UserService userService;


    @Test
    public void testAspectJByXml() {
        userService.query("select * from tableName");
    }
}

在这里插入图片描述

基于注解实现

前面的步骤不需要改变,主要变化的是第三步,在增强类中添加注解:

@Component("myAspect")
@Aspect
public class MyAspect {
    @Before(value = "execution(void com..UserServiceImpl.query(*))")
    public void before(){
        System.out.println("注解方式 before..........");
    }
}

4、在Spring文件中配置aop:

<!--注解方式-->
    <!--配置切面类-->
    <context:component-scan base-package="com.lks.aspectJ"></context:component-scan>
    <!--开启AOP自动代理-->
    <aop:aspectj-autoproxy/>

另外出了前置通知以外,还有后置通知、最终通知、环绕通知、异常抛出通知,共五种通知类型:
前置通知
***执行时机:目标对象方法之前执行通知
***配置文件:<aop:before method=“before” pointcut-ref=“myPointcut”/>
***应用场景:方法开始时可以进行校验
后置通知
***执行时机:目标对象方法之后执行通知,有异常则不执行了
***配置文件:<aop:after-returning method=“afterReturning” pointcut-ref=“myPointcut”/>
***应用场景:可以修改方法的返回值
最终通知
***执行时机:目标对象方法之后执行通知,有没有异常都会执行
***配置文件:<aop:after method=“after” pointcut-ref=“myPointcut”/>
***应用场景:例如像释放资源
环绕通知
***执行时机:目标对象方法之前和之后都会执行。
***配置文件:<aop:around method=“around” pointcut-ref=“myPointcut”/>
***应用场景:事务、统计代码执行时机
异常抛出通知
***执行时机:在抛出异常后通知
***配置文件:<aop:after-throwing method=" afterThrowing " pointcut- ref=“myPointcut”/>
***应用场景:包装异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值