Spring笔记(三)——注解方式实现AOP

项目搭建

项目用到的jar包结构如下:
注解方式实现AOP
除了Spring基本的开发包,还包括spring的传统AOP的开发的包:
spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
aspectJ的开发包:
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
Spring的配置文件的具体的AOP的schema约束如下:

<beans xmlns="http://www.springframework.org/schema/beans"
           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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    </beans>

applicationContext.xml内容如下:

<?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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--开启注解扫描,可以扫描com.mq包下的所有bean  -->
<context:component-scan base-package="com.mq"/>

<!--开启AOP的自动代理,开启后,可以使用AOP的注解  -->
<aop:aspectj-autoproxy/>

</beans>

注意:context:component-scan base-package=”com.mq” 是开启注解扫描,扫描特定包结构下的java文件
aop:aspectj-autoproxy 是开启自动代理,开启后才可以使用AOP的注解

目标类的代码如下:

@Component(value="myService")
public class MyServiceImpl implements MyService {

    @Override
    public void saveUser() {
        System.out.println("业务层保存用户");
    }

}

该类只有一个很简单的方法,saveUsere();
注意MyServiceImpl 实现了MyService接口,这个在AOP开发中非常重要。

切面类的代码如下:

@Aspect
@Component(value="myAspect")
public class MyAspect {

     @Before(value="execution(public void com.mq.service.MyServiceImpl.saveUser())")
     public void log(){
         System.out.println("记录日志...");
     }

}

声明一个切面类,需要用到@Aspect注解。
@Before是通知类型,表示执行saveUser方法之前,执行log方法。value值是切入点表达式。

通知类型的注解类型
* @Before – 前置通知
* @AfterReturing – 后置通知
* @Around – 环绕通知(目标对象方法默认不执行的,需要手动执行)
* @After – 最终通知
* @AfterThrowing – 异常抛出通知

测试类如下:

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration("classpath:applicationContext.xml") 
public class MyTest {
     @Resource(name="myService")
     private MyService myService;//切记不能使用MyServiceImpl创建对象,否则会报错。

    @Test
    public void f1(){
        myService.saveUser();

    }
}

注意:必须使用接口的引用调用方法,如果使用MyServiceImpl对象,会报错。

执行结果:

记录日志...
业务层保存用户

切面类还有另外一种写法,将通知和切入点分开写。
配置通用的切入点

@Aspect
@Component(value="myAspect")
public class MyAspect {

 @After(value="MyAspect.fn()")
     public void log(){
         System.out.println("记录日志...");
     }
     @Pointcut(value="execution(public void com.mq.service.MyServiceImpl.saveUser())")
     public void fn(){}
}

@Pointcut是切入点的注解。
@After的值是”类名.切入点方法名“
配置通用切入点的好处是,不用经常写繁琐的切入点表达式,可以简化开发

环绕通知

环绕通知的方法需要手动执行,比较特殊。环绕通知的代码如下:

@Aspect
@Component(value="myAspect")
public class MyAspect {
     @Pointcut(value="execution(public void com.mq.service.MyServiceImpl.saveUser())")
     public void fn(){}

    /**
     * 环绕通知
     */
    @Around(value="MyAspect.fn()")
    public void around(ProceedingJoinPoint joinPoint){
        System.out.println("环绕通知执行前");
        try {
            // 让目标对象的方法执行
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("环绕通知执行后");
    }

}

执行结果:

环绕通知执行前
业务层保存用户
环绕通知执行后

java.lang.ClassCastException: com.sun.proxy.$Proxy* cannot be cast to **

在使用AOP的时候,一不小心就会遇到这样的异常。
因为AOP底层采用动态代理的方式实现,一种是常规的JDK,另一种是CGLIB。当代理对象实现接口时,默认使用JDK的方式动态创建代理对象。如果代理对象没有实现任何接口,则采用CGLIB的方式。
一般情况下,代理对象都会实现接口。
解决方法

如果代理对象实现了接口,那么就使用接口的引用调用方法,不能直接使用代理类的引用。简而言之,使用多态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Spring AOP笔记和源码讲解,我可以给你简单介绍一下。 Spring AOPSpring框架中的一个重要模块,提供了基于代理的AOP实现AOP(Aspect Oriented Programming)面向切面编程,是一种编程思想,它通过将横切关注点与业务逻辑分离,使得系统的关注点更加清晰,代码更加简洁易懂,同时也提高了代码的可维护性和可扩展性。 在Spring AOP中,切面(Aspect)是一个类,它包含了通知(Advice)和切点(Pointcut)。通知是在切点上执行的操作,例如在方法执行前或执行后执行一些额外的逻辑。而切点则是一个表达式,用于匹配目标对象中的方法,从而确定哪些方法会被通知所影响。 Spring AOP提供了四种通知类型,分别是: 1. 前置通知(Before advice):在目标方法执行之前执行。 2. 后置通知(After returning advice):在目标方法执行之后执行,在目标方法没有抛出异常的情况下。 3. 异常通知(After throwing advice):在目标方法抛出异常后执行。 4. 最终通知(After advice):无论目标方法是否抛出异常,最终通知都会执行。 除了通知之外,Spring AOP还提供了环绕通知(Around advice),它可以在目标方法执行前和执行后执行一些额外的逻辑,并且可以控制目标方法的执行。 在Spring AOP中,代理是通过JDK动态代理或者CGLIB字节码生成技术生成的。如果目标对象实现了接口,则使用JDK动态代理实现代理;如果目标对象没有实现接口,则使用CGLIB字节码生成技术实现代理。 在Spring AOP中,通知和切点都可以使用注解方式来声明。例如,使用@Aspect注解声明一个切面类,使用@Before、@After、@AfterReturning、@AfterThrowing和@Around注解声明通知方法,使用@Pointcut注解声明切点表达式。 关于Spring AOP源码讲解,它的实现主要涉及到以下几个类: 1. AdvisedSupport类:封装了目标对象、切面和通知等信息。 2. ProxyFactory类:用于生成代理对象的工厂类。 3. AopProxy接口:代理对象的接口。 4. JdkDynamicAopProxy和CglibAopProxy类:实现AopProxy接口,分别用于基于JDK动态代理和CGLIB字节码生成技术的代理对象。 以上是Spring AOP笔记和简单源码讲解,希望能对你有所帮助。如果有什么不清楚的地方,可以继续问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值