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);

结果

扫描二维码关注公众号,回复: 1457955 查看本文章
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...

执行顺序图解



猜你喜欢

转载自blog.csdn.net/start_mao/article/details/80551751