Spring入门四(基于注解的AOP编程、切面、切点、execution用法、五种Advice)

AOP的基本概念:面向切面编程,作用类似于反射代理。在目标方法执行前后可自动的执行其他代码(称为增强)。其他代码又被称为切面。我们要关注的是如何写其他代码而不是如何调用其他代码。因此称之为面向切面编程。

AOP编程的主要步骤

  1. 编写切面类,由多个额外的方法组成
  2. 声明pointcut,定义要增强的点,即目标方法
  3. 声明advice,指明在被代理对象的方法返回值后抛出异常后周围执行要执行的代码。
    1. 下面开始code...
      定义接口:接口中定义要增强的方法。早期版本只能对接口中的方法增强,后来的版本可以对普通类中的方法进行增强。
public interface EmailDao {
    public void send();
    public void receive();
}

接口的实现类:

@Component//对象的创建交给容器来管理
public class EmailDaoImpl implements EmailDao {
    @Override public void send() {
        System.out.println("发送邮件");
    }
    @Override public void receive() {
        System.out.println("收到邮件");
    }
}

定义切面:@Aspect表示这是一个切面类,切面类也是交给spring容器来管理的。用execution语句来指定增强点。可以在一个空方法上用@Pointcut来指定增强点,之后可以用方法名加扩号来取代execution语句。如下面代码中第三个方法上面。但是早期的一些版本也不支持。
execution语句解释:execution(* com.AOP.EmailDao.se*(…)),第一个*表示访问权限为任意;后面的路径表示该路径下的以se开头的方法,不写se表示任意方法,参数任意。

@Aspect
@Component
public class MyService {
    @Pointcut("execution(* com.AOP.EmailDao.re*(..))")
    public void point(){}
    @Before("execution(* com.AOP.EmailDao.se*(..))")//目标方法执行之前执行下面的代码
    public void send()
    {
        System.out.println("发送邮件之前");
    }
    @After("point()")//也可以写成@After("execution(* com.AOP.EmailDao.re*(..))"),表示该结构下的以re开头的方法执行完后都会执行以下方法。
    public void receive()
    {
        System.out.println("接受邮件之后");
    }
}

因为是基于注解,所有没有ApplicatioonContext.xml文件,要通过java类来配置:

@Configurable
@EnableAspectJAutoProxy//开启代理,一定要加
public class MyConfig {
    @Bean("email")
    public EmailDao getEmailDao()
    {
        return new EmailDaoImpl();
    }
    @Bean
    public AllService getAllService()
    {
        return new AllService();
    }
}

main方法:

public class Main {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(MyConfig.class);
        EmailDao email=(EmailDao)context.getBean("email");
        email.send();
        email.receive();
    }
}

运行结果:

发送邮件之前
发送邮件
收到邮件
接受邮件之后

验证能否对普通类中的方法进行增强,将切点的位置移动到一个普通类的一个普通方法(不是继承来的)。对该方法进行增强。

@Component
public class test {
    public void show()//要增强的方法
    {
        System.out.println("Hello world");
    }
}

切面类中:

@Before("execution(* com.AOP.test.*(..))")
 public void beforeNormalMethod()
 {
     System.out.println("hi............");
 }

配置类中:

 @Bean
 public test getTest()
 {
     return new test();
 }

main方法中:

test t=context.getBean(test.class);
t.show();

运行结果:

hi............
Hello world


返回值后进行增强:
切面类:

 @AfterReturning(value = "execution(* com.AOP.test.*(..))",returning = "retVal")
    public void afterReturnMethod(Object retVal)
    {
        System.out.println("有返回值"+((Integer)retVal+666));//对返回值加666后进行输出
    }

被切点命中的方法:

public int show()
{
    return 0;
}

运行结果:

有返回值666


方法抛出异常时进行增强:

@AfterThrowing(value = "execution(* com.AOP.test.*(..))",throwing = "exc")
    public void afterThrowingMethod(Exception exc)
    {
        System.out.println("有异常了-----"+exc);
    }

被命中的方法:

public int show()
    {
        return 10/0;//会抛出异常
    }

运行结果:

有异常了-----java.lang.ArithmeticException: / by zero


方法周围执行增强方法,相当于反射代理

 @Around("execution(* com.AOP.test.*(..))")
    public void aroundMethod(ProceedingJoinPoint proceedingJoinPoint)throws Throwable
    {
        System.out.println("执行目标方法之前");
        proceedingJoinPoint.proceed();//执行目标方法
        System.out.println("执行目标方法之后");
    }
    public void show()
    {
        System.out.println("this is show method");
    }

运行结果:

执行目标方法之前
this is show method
执行目标方法之后

上一篇
---The End---
下一篇
Spring AOPSpring框架中的一个重要模块,它提供了面向切面编程AOP)的支持。AOP是一种编程思想,它可以在不改变原有代码的情况下,通过在程序运行时动态地将代码“织入”到现有代码中,从而实现对原有代码的增强。 Spring AOP提供了基于注解AOP实现,使得开发者可以通过注解的方式来定义切面切点和通知等相关内容,从而简化了AOP的使用。 下面是一个基于注解AOP实现的例子: 1. 定义切面类 ```java @Aspect @Component public class LogAspect { @Pointcut("@annotation(Log)") public void logPointcut() {} @Before("logPointcut()") public void beforeLog(JoinPoint joinPoint) { // 前置通知 System.out.println("执行方法:" + joinPoint.getSignature().getName()); } @AfterReturning("logPointcut()") public void afterLog(JoinPoint joinPoint) { // 后置通知 System.out.println("方法执行完成:" + joinPoint.getSignature().getName()); } @AfterThrowing(pointcut = "logPointcut()", throwing = "ex") public void afterThrowingLog(JoinPoint joinPoint, Exception ex) { // 异常通知 System.out.println("方法执行异常:" + joinPoint.getSignature().getName() + ",异常信息:" + ex.getMessage()); } } ``` 2. 定义业务逻辑类 ```java @Service public class UserService { @Log public void addUser(User user) { // 添加用户 System.out.println("添加用户:" + user.getName()); } @Log public void deleteUser(String userId) { // 删除用户 System.out.println("删除用户:" + userId); throw new RuntimeException("删除用户异常"); } } ``` 3. 在配置文件中开启AOP ```xml <aop:aspectj-autoproxy/> <context:component-scan base-package="com.example"/> ``` 在这个例子中,我们定义了一个切面类LogAspect,其中通过@Aspect注解定义了一个切面,通过@Pointcut注解定义了一个切点,通过@Before、@AfterReturning和@AfterThrowing注解分别定义了前置通知、后置通知和异常通知。 在业务逻辑类中,我们通过@Log注解标注了需要增强的方法。 最后,在配置文件中,我们通过<aop:aspectj-autoproxy/>开启了AOP功能,并通过<context:component-scan>扫描了指定包下的所有组件。 这样,当我们调用UserService中的方法时,就会触发LogAspect中定义的通知,从而实现对原有代码的增强。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值