Spring(一)——使用注解方式开发Spring AOP

 

AOP的基本概念

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知。

(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用(就是要拦截的方法,在这个方法前后织入对应的通知)。

(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around。

(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式。

接口

public interface UserService {
    void printUser(User user);
}

接口的实现类(被代理对象)

//被代理的对象
@Component
public class UserServiceImpl implements UserService {

	//连接点(从动态代理角度看,就是被拦截的方法,在这个方法前后织入对应的AOP通知)
	@Override
	public void printUser(User user) {
		System.out.println("name:"+user.getName()+"  age:"+user.getAge());
	}

切面类

//使用@Aspect注解一个类Spring ioc容器就会认为这是一个切面
//切面
@Aspect
public class UserAspect {
    //前置通知(在被代理对象的方法前调用) *代表任意返回类型     printUser被拦截的方法    (..)任意参数
	@Before("execution( * aop.UserServiceImpl.printUser(..))")
    public void before(){
    	System.out.println("before...");
    }
	//后置通知(在被代理对象的方法后调用)
    @After("execution( * aop.UserServiceImpl.printUser(..))")
    public void after(){
    	System.out.println("after...");
    }
    //返回通知(在被代理对象的方法正常返回后调用)
    @AfterReturning("execution( * aop.UserServiceImpl.printUser(..))")
    public void afterReturning(){
    	System.out.println("afterReturning...");
    }
    //异常通知(在被代理对象的方法抛出异常后调用)
    @AfterThrowing("execution( * aop.UserServiceImpl.printUser(..))")
    public void afterThrowing(){
    	System.out.println("afterThrowing...");
    }
}

AopConfig.java

@EnableAspectJAutoProxy//开启自动代理
@ComponentScan
@Configuration
public class AopConfig {
	
	@Bean
    public UserAspect getUserAspect(){
    	return new UserAspect();
    }

}

测试

AnnotationConfigApplicationContext ioc=
				new AnnotationConfigApplicationContext(AopConfig.class);
		UserService uService=ioc.getBean(UserService.class);
		User user=new User();
		user.setName("张三");
		user.setAge(18);
		uService.printUser(user);

结果

before...
name:张三  age:18
after...
afterReturning...

如果认为每次都写"execution( * aop.UserServiceImpl.printUser(..))"比较麻烦可以用@Pointcut注解来定义切点

//使用@Aspect注解一个类Spring ioc容器就会认为这是一个切面
//切面
@Aspect
public class UserAspect {

	//@Pointcut注解定义一个切点  *代表任意返回类型     printUser被拦截的方法    (..)任意参数
    @Pointcut("execution( * aop.UserServiceImpl.printUser(..))")
	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...");
    }
}

给通知传递参数(以前置通知为例)

 //前置通知(在被代理对象的方法前调用)
	@Before("execution( * aop.UserServiceImpl.printUser(..))&&args(user)")
    public void before(User user){
    	System.out.println("before..."+user.getName());
    }

需要注意的是被代理对象的接口存在并不是必须的,如果有接口Spring会采用JDK动态代理,并织入对应的通知,如果不存在则使用CGLIB动态代理。

二、多切面

Spring不仅支持单切面,同样对多切面有着很好的支持。我们将接口去掉修改UserService代码,并定义多个切面。

//被代理的对象
@Component
public class UserService{

	//连接点(被拦截的方法)
	public void printUser(User user) {
		System.out.println("name:"+user.getName()+"  age:"+user.getAge());
	}

}

共有三个切面分别是UserAspect1,UserAspect2,UserAspect3。切面一代码如下

//切面1
@Aspect
@Order(1)
public class UserAspect1 {
    
	@Before("execution( * aop.UserService.printUser(..))")  
    public void before(){
    	System.out.println("before1...");
    }
	
	@After("execution( * aop.UserService.printUser(..))")
    public void after(){
    	System.out.println("after1...");
    }
	
    @AfterReturning("execution( * aop.UserService.printUser(..))")
    public void afterReturning(){
    	System.out.println("afterReturning1...");
    }
    
    @AfterThrowing("execution( * aop.UserService.printUser(..))")
    public void afterThrowing(){
    	System.out.println("afterThrowing1...");
    }
}

@Order(1)注解用来保证切面在织入时的执行顺序,这里传入1代表第一个执行

AopConfig.java

@EnableAspectJAutoProxy//开启自动代理
@ComponentScan
@Configuration
public class AopConfig {
		
	@Bean
    public UserAspect1 getUserAspect1(){
    	return new UserAspect1();
    }
	@Bean
    public UserAspect2 getUserAspect2(){
    	return new UserAspect2();
    }
	@Bean
    public UserAspect3 getUserAspect3(){
    	return new UserAspect3();
    }
}

测试

AnnotationConfigApplicationContext ioc=new AnnotationConfigApplicationContext(AopConfig.class);
		UserService userService =ioc.getBean(UserService.class);
		User user=new User();
		user.setName("李四");
		user.setAge(20);
		userService.printUser(user);

测试结果

before1...
before2...
before3...
name:李四  age:20
after3...
afterReturning3...
after2...
afterReturning2...
after1...
afterReturning1...

执行顺序图解

 

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、付费专栏及课程。

余额充值