前面介绍了spring是一种Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)其中介绍了IOC
现在我们来介绍一下AOP:
AOP的简介
AOP:面向切面编程,AOP是OOP的延续,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块。
AOP的作用
作用;在不修改代码的同时为程序增强功能,多个类的公共行为封装到一个可重用模块。编写业务时只关注于核心功能 ,不再考虑事务、日志等公共功能,减轻了编码负担,更专注于业务。
AOP术语
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
配置版
aop:pointcut 是切入点配置
其中的核心是expression,通过表达式控制切面应用的范围
execution(访问修饰符 返回值 包名.类名.方法名(参数类型,参数类型…))
语法:
/**
* 输出通知类
*/
public class LogAdvise {
public void beforeLog(){
System.out.println("方法开始执行!");
}
public void afterLog(){
System.out.println("方法后置执行!");
}
public void afterReturning(){
System.out.println("方法返回了数据");
}
public void afterThrowing(){
System.out.println("方法抛出了异常");
}
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around方法名:" + joinPoint.getSignature().getName());
System.out.println("around --前置");
//原来方法
joinPoint.proceed();
System.out.println("around --后置");
}
}`
<?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:context="http://www.springframework.org/schema/context"
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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置包的扫描-->
<context:component-scan base-package="com.blb.aop_demo"></context:component-scan>
<!--配置通知类-->
<bean id="logAdvise" class="com.blb.aop_demo.util.LogAdvise"></bean>
<!--配置切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pc" expression="execution(* com.blb.aop_demo.service.*Service.*(..))"/>
<!--配置切面 ref是通知类的bean-->
<aop:aspect id="aspect1" ref="logAdvise">
<!--前置通知 method是对应的通知方法 pointcut-ref是切入点-->
<aop:before method="beforeLog" pointcut-ref="pc"></aop:before>
<!--后置-->
<aop:after method="afterLog" pointcut-ref="pc"></aop:after>
<!--后置返回-->
<aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>
<!--后置抛异常-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pc"></aop:after-throwing>
<!--环绕-->
<aop:around method="around" pointcut-ref="pc"></aop:around>
</aop:aspect>
</aop:config>
</beans>
测试:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");
GoodsService goodsService = context.getBean(GoodsService.class);
goodsService.queryGoods();
goodsService.queryGoodsById(1);
goodsService.createGoods();
goodsService.updateGoods();
goodsService.deleteGoodsById(1);
测试结果成功
AOP注解配置
@Aspect 切面,配置到切面类上
@PointCut(“表达式”) 配置切入点,加在方法上
@Before 配置前置通知方法
@After 配置后置通知方法
@Around 配置环绕通知方法
@AfterReturning 配置后置返回值通知方法
@AfterThrowing 配置后置抛出异常通知方法
/日志切面类
@Aspect
public class LogAspects {
@Pointcut("execution(public int com.enjoy.cap10.aop.Calculator.*(..))")
public void pointCut(){};
//@before代表在目标方法执行前切入, 并指定在哪个方法前切入
@Before("pointCut()")
public void logStart(){
System.out.println("除法运行....参数列表是:{}");
}
@After("pointCut()")
public void logEnd(){
System.out.println("除法结束......");
}
@AfterReturning("pointCut()")
public void logReturn(){
System.out.println("除法正常返回......运行结果是:{}");
}
@AfterThrowing("pointCut()")
public void logException(){
System.out.println("运行异常......异常信息是:{}");
}
@Around("pointCut()")
public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("@Arount:执行目标方法之前...");
Object obj = proceedingJoinPoint.proceed();//相当于开始调div地
System.out.println("@Arount:执行目标方法之后...");
return obj;
}