提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Spring两大核心之一aop,也就是用切面管理类
一;横切关注点;
二;通知
三;切面;封装通知方法的类(也就是管理通知方法的类)
*
四;目标;被代理的对象
五;代理;向目标对象应用通知后创建的代理对象
六;连接点,需要将通知接入的点(逻辑概念)
七;切入点;定位连接点的方式(也就是最后会将通知插入到核心代码的位置)
总结;找到目标的横切关注点,写出需要的通知, 交给切面管理,然后aop会自动创建代理对象(动态代理)之后根据切入点加载到方法中去
首先我们要知道,我们使用aop需要两个东西,一个是需要代理的类,也就是目标类,一个是如何代理的类,也就是切面类,这两个类都需要我们创建
首先创建我们需要代理的类
注意添加@Component注解加载进ioc中
@Component
public class calculatorImp implements calcolator{
public int add(int i , int j){
int sum = i + j;
return sum;
}
}
然后我们创建切面类,也就是calculatorImp的切面类
注意要添加@Aspect注解,让ioc知道这是一个切面
@Component
@Aspect
public class LoggerAspect {
public void BeforeMessage(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();//获取对应方法的签名信息
Object[] args = joinPoint.getArgs();//获取对应方法的参数信息
System.out.println("前置通知LoggerAspect");
System.out.println("方法名为:"+signature);
System.out.println("参数名为:"+ Arrays.toString(args));
}
}
这时候我们如何让ioc知道,LoggerAspect 是calculatorImp 的切面呢----添加@Before注解
将上面的LoggerAspect 添加@Before注解
@Component
@Aspect
public class LoggerAspect {
/*
* 切入点表达式;设置在标识通知的注解value属性中
* execution(public int com.ligong.spring.pojo.calculatorImp.add(..)
* 表示返回值为int的com.ligong.spring.pojo包下的calculatorImp类中的任意参数的add方法(..表示任意参数列表)
*/
//在切面中,需要通过指定的注解将方法标识为通知方法
@Before("execution(* com.ligong.spring.pojo.calculatorImp.add(..))")
public void BeforeMessage(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();//获取对应方法的签名信息
Object[] args = joinPoint.getArgs();//获取对应方法的参数信息
System.out.println("前置通知LoggerAspect");
System.out.println("方法名为:"+signature);
System.out.println("参数名为:"+ Arrays.toString(args));
}
}
最后将这两个类加载进ioc容器中
加载ioc容器的代码
aop注意事项;
切面类和目标类都要交给ioc管理
切面类必须通过@Aspect注解标识为一个切面
在Spring配置文件中设置aop:aspectj-autoproxy/开机基于注解的aop
扫描文件,也就是说,aop的基础是ioc
<context:component-scan base-package="com.ligong.spring.pojo"></context:component-scan>
<!--开启基于注解的aop;如果想实现通过注解管理切面这个标签必须配置-->
<aop:aspectj-autoproxy/>
这里我们学习一些获取切面的一些信息,比如切面中的通知的方法名,获取通知的参数等等
如果想要获取参数的信息,需要在通知方法的参数位置,设置joninpoint类型的参数,就可以获取连接点所对应方法的信息
例如;
在切面LoggerAspect的BeforeMessage中设置joninpoint
问题引入;
现在有一种情况,例如我们有两个切面,我们需要切面A先知性之后切面B再执行,该怎么实现呢?
----遇到这种考虑切面优先级的情况,我们需要使用order注解,设置切面优先级(默认order中的参数越小,优先级越高)
例子见MetondAspect中的oder标签
创建两个切面
切面A;
@Component
@Aspect
public class LoggerAspect {
@Before("execution(public int com.ligong.spring.pojo.calculatorImp.add(..))")
public void BeforeMessage(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();//获取对应方法的签名信息
Object[] args = joinPoint.getArgs();//获取对应方法的参数信息
System.out.println("前置通知LoggerAspect");
System.out.println("方法名为:"+signature);
System.out.println("参数名为:"+ Arrays.toString(args));
}
}
切面B;
Order注解设置切面优先级,数字越小优先级越高
@Component
@Aspect
@Order(1)//Order注解设置切面优先级,数字越小优先级越高
public class MetondAspect {
@Before("execution(public int com.ligong.spring.pojo.calculatorImp.add(..))")
public void BeforeMessage() {
System.out.println("前置通知MetondAspect");
}
}
测试
public class testAspect {
@Test
public void test1(){
//因为aop也是给ioc管理的,所以一样的先获取ioc
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("Aop-annotation.xml");
//注意这里不能直接获取calculatorImp.class,因为aop是通过动态代理生成了calculatorImp.class的代理类
//如果在这里还是直接获取calculatorImp.class就会空指针;NoSuchBeanDefinitionException
//calculatorImp bean1 = ioc.getBean(calculatorImp.class);报错
//那么因为我们知道jdbc的动态代理是必须实现和被代理类同样的接口的,我们就可以通过接口来获取到该bean
calcolator bean = ioc.getBean(calcolator.class);
bean.add(1,1);
}
}
测试结果
前置通知MetondAspect
前置通知LoggerAspect
方法名为:int com.ligong.spring.pojo.calcolator.add(int,int)
参数名为:[1, 1]