Java教程

注解开发Spring AOP

本文主要是介绍注解开发Spring AOP,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

AOP的概念和理解:使用画图的方式理解面向切面编程(AOP)

AOP的术语以及XML配置方式快速入门

(1)创建目标接口以及实现类

package com.ssm.aop.service;

import com.ssm.aop.game.Role;

public interface RoleService {
    public void printRole(Role role);
}
package com.ssm.aop.service.Impl;

import com.ssm.aop.game.Role;
import com.ssm.aop.service.RoleService;
import org.springframework.stereotype.Component;

@Component
public class RoleServiceImpl implements RoleService {

    @Override
    public void printRole(Role role) {
        System.out.println("{id: "+role.getId()+", "
        +"role_name:"+role.getRoleName()+", "
        +"note:"+role.getNote()+"}");
    }
}

(2)创建切面类(用于增强目标类的方法)

package com.ssm.aop.aspect;

import org.aspectj.lang.annotation.*;

@Aspect
public class RoleAspect {
    @Before("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))")
    public void before()
    {
        System.out.println("before...");
    }
    @After("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))")
    public void after()
    {
        System.out.println("after...");
    }
    @AfterReturning("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))")
    public void afterReturning()
    {
        System.out.println("afterReturning...");
    }
    @AfterThrowing("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))")
    public void afterThrowing()
    {
        System.out.println("afterThrowing...");
    }

}

在类的上方加上@Aspect注解,就表明该类为切面类

@Before:添加该注解的方法表明该方法在被代理对象的方法前调用,即前置通知

@After:添加该注解的方法表明该方法在被代理对象的方法后调用,即后置通知

@AfterReturning:添加该注解的方法表明该方法在被代理对象的方法正常返回后调用。

@AfterThrowing:添加该注解的方法表明该方法在被代理对象的方法抛出异常后调用。

方法上的注解括号中的配置项(定义了execution的正则表达式,来匹配对应的切点)用于定义切点:

表达式的语法:

execution([修饰符]返回值类型 包名.类名.方法名(参数))

  • 访问的修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用*代表任意
  • 包名与类名之间一个点.代表当前包下的类,两个点..表示当前包及其子包下的类
  • 参数列表可以使用两个点..表示任意个数,任意类型的参数列表。

以下面的表达式为例:

execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))

execution:代表执行方法时会触发

*:代表任意返回类型的方法

com.ssm.aop.service.Impl.RoleServiceImpl:代表类的全限定名

printRole:被拦截的方法名称

(..):任意的参数

上述切面类中,切点的定义是重复的代码,比较麻烦,可以通过引入@Pointcut定义一个切点就可以避免该麻烦

在一个没有任何逻辑的方法上方定义@Pointcut注解,配置项为切点的表达式即可,在使用时只要在配置项配置没有逻辑的方法名即可。

改进后的代码如下

package com.ssm.aop.aspect;

import org.aspectj.lang.annotation.*;

@Aspect
public class RoleAspect {

    @Pointcut("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))")
    public void print()
    {
        
    }
    @Before("print()")
    public void before()
    {
        System.out.println("before...");
    }
    @After("print()")
    public void after()
    {
        System.out.println("after...");
    }
    @AfterReturning("print()")
    public void afterReturning()
    {
        System.out.println("afterReturning...");
    }
    @AfterThrowing("print()")
    public void afterThrowing()
    {
        System.out.println("afterThrowing...");
    }

}

(3)配置

要使得上述的注解有效,要先启动AspectJ自动代理,这样Spring才会生成动态代理对象。

配置代码如下:

package com.ssm.aop.config;

import com.ssm.aop.aspect.RoleAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.ssm.aop")
public class AopConfig {
    @Bean
    public RoleAspect getRoleAspect()
    {
        return new RoleAspect();
    }
}

@EnableAspectJAutoProxy

 @Bean
    public RoleAspect getRoleAspect()
    {
        return new RoleAspect();
    }

该部分代码就代表了启动了AdpectJ框架的自动代理

另一种启用自动代理是通过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: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
">
    <aop:aspectj-autoproxy/>
    <bean id="roleAspect" class="com.ssm.aop.aspect.RoleAspect"/>
    <bean id="roleService" class="com.ssm.aop.service.Impl.RoleServiceImpl"/>

</beans>

可以看到XML中将RoleAspect切面类和RoleServiceImpl目标类作为bean加入Ioc容器,相当于注解中的@Bean和@Component

<aop:aspectj-autoproxy>跟注解@EnableAspectJautoProxy作用相同,启用自动代理功能。

(4)测试

测试代码如下:

import com.ssm.aop.config.AopConfig;
import com.ssm.aop.game.Role;
import com.ssm.aop.service.RoleService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);//使用config类配置
       // ApplicationContext ctx=new ClassPathXmlApplicationContext("application-config.xml");//使用xml配置文件
        RoleService roleService = (RoleService) ctx.getBean(RoleService.class);
        Role role = new Role();
        role.setId(1L);
        role.setRoleName("role_name_1");
        role.setNote("note_1");
        roleService.printRole(role);
        System.out.println("####################");
        //测试异常通知
        role = null;
        roleService.printRole(role);
    }
}

运行结果如下图;

 在测试代码中特意创建了一个空对象来触发异常通知。

在没有错误的情况下,可以看到首先调用前置通知,然后调用printRole方法,再调用了成功返回的通知,最后调用后置通知。

在抛出异常的情况下,首先调用了前置通知,然后调用pringRole方法时出现异常,则调用异常通知输出afterThrowing,最后调用后置通知。

也就是说无论调用pringRole成功与否,都会调用后置通知。

这篇关于注解开发Spring AOP的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!