Spring AOP
首先需要了解springAOP的一些重要概:
1.切点:定义的就是为哪些方法增加功能
2.通知:定义的就是何时何事
3.切面: 切面是一个类,包含了切点和通知的类
4.织入:把切面整合到目标类的过程
5.接入点:里面保存着当前执行的方法的信息
springAOP利用了AspectJ个框架的配置方式.,就是里面的注解所以需要先导入一个jar包.
具体实现:
1.创建一个切面,即一个类,用@Aspect注解把这个类标记为切面,
切点: 在切面里面为指定的类的方法添加切点.
通知: 在围绕切点选择想要在什么时候增强什么功能.
@Aspect
@Component
public class LogAspect {
//1.切点
//切点实际上就是一个表达式,规定为哪些方法做增强的表达式
//表示Service类中的所有方法
@Pointcut("execution(* com.lanou.demo.service.impl.*.*(..))")
public void allServiceMethod(){
}
//2.通知
//前置通知
@Before("allServiceMethod()") //该注解默认等于 @Before(value = "allServiceMethod()")
public void before(JoinPoint jp){
//JoinPoint接入点:
// 可以根据需要获取下面的相关信息
//获取被代理对象
Object target = jp.getTarget();
//获取方法签名
Signature signature = jp.getSignature();
//获取方法的参数
Object[] args = jp.getArgs();
System.out.println("方法之前执行");
}
//后置通知
@After("allServiceMethod()")
public void after(JoinPoint jp){
System.out.println("方法执行后");
}
//方法正常执行的通知
//returning参数:接受参数
@AfterReturning(value = "allServiceMethod()",returning = "value")
public void returnLog(JoinPoint jp,Object value){
System.out.println("方法正常执行"+value);
}
//异常通知
@AfterThrowing(value = "allServiceMethod()",throwing = "ex")
public void throwLog(JoinPoint jp,Exception ex){
System.out.println("方法异常了");
}
//环绕通知 :相当于在原来方法周围添加功能.
//ProceedingJoinPoint 是JoinPoint 的子类
@Around("allServiceMethod()")
public Object around(ProceedingJoinPoint jp){
try {
long start = System.currentTimeMillis(); //写在原来方法的前面相当于前置通知
Object proceed = jp.proceed(); //这是执行的原来的方法
long time = System.currentTimeMillis()-start; //写在原来方法后面相当于后置通知
System.out.println("运行时长"+time);
return proceed;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
2.创建好切面后,需要在spring配置文件中配置aop,让spring根据注解自动加载切面
<?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:mvc="http://www.springframework.org/schema/mvc" 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/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.lanou.demo"/>
<mvc:annotation-driven/>
<aop:config>
<aop:pointcut id="service" expression="execution(* com.lanou.demo.service.impl.*.*(..)))"/>
<aop:aspect ref="logAspect" order="1">
<aop:before method="before" pointcut-ref="service"/>
</aop:aspect>
</aop:config>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--配置可以根据注解自动加切面的功能-->
<!--第一种的配置方式:常用-->
<aop:aspectj-autoproxy/>
<!--第二种配置方式:
这种配置方式不需要再用注解标记,而是在这里面指定要加载的类和方法
里面的参数跟注解方式注解的参数对应.
-->
<!--<aop:config>-->
<!--<aop:pointcut id="service" expression="execution(* com.lanou.demo.service.impl.*.*(..)))"/>-->
<!--<aop:aspect ref="logAspect" order="1">-->
<!--<aop:before method="before" pointcut-ref="service"/>-->
<!--</aop:aspect>-->
<!--</aop:config>-->
</beans>
3.创建一个类,并spring注解标记.里面写原来执行的功能.
@Service
public class BookSericeImpl implements BookSerice {
@Override
public void addOne(BokBean bokBean) {
System.out.println("执行逻辑:插入一本书");
}
@Override
public void deletOne(Long bookId) {
System.out.println("执行逻辑:删除一本书");
//睡眠1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.调用bookserviceImpl中的方法,(这里用spring测试类测试)
//spring测试类注解.
@RunWith(SpringJUnit4ClassRunner.class)
//加载spring的配置文件
@ContextConfiguration("classpath:application-context.xml")
public class BookSericeImplTest {
@Resource
private BookSerice bookSerice;
@Test
public void text1() {
//调用原来方法
this.bookSerice.deletOne(33L);
}
}
执行结果如下:
会发现为类或方法配置好切点后,当执行该方法时,spring会自动为该方法添加增强的功能.
INFO: HV000001: Hibernate Validator 6.0.16.Final
方法之前执行
执行逻辑:删除一本书
运行时长1002
方法执行后
方法正常执行null
Process finished with exit code 0