Spring学习笔记(二)
参考文章及资料
参考文章:
https://www.cnblogs.com/joy99/p/10941543.html
https://cloud.tencent.com/developer/article/1441626
参考资料:
《 JavaEE的颠覆者 - Spring Boot 实战 》
《58集精通java教程Spring框架开发 - 黑马程序员》
Spring AOP
AOP
什么是AOP
AOP(Aspect Oriented Program):面向切面编程,它是一种编程思想,是面向对象编程(OOP)的一种补充。
- aop:面向切面(方面)编程,扩展功能不修改源代码实现。
- aop采取横向抽取机制,取代了传统纵向继承体系重复性代码。
- aop底层使用动态代理实现:
- 第一种情况,有接口情况,使用动态代理创建接口实现类代理对象
- 第二种情况,没有接口情况,使用动态代理创建类的子类代理对象
为什么需要AOP
Spring的AOP的存在目的是为了解耦。AOP可以让一组类共享相同的行为。在OOP中只能通过继承类和实现接口,在使代码的耦合度增强,且类继承只能单继承,阻碍更多行为添加到一组类上,AOP弥补了OOP的不足。
Spring的AOP操作
操作之前需要先了解一些AOP的相关术语
Aop操作术语
Advice(通知/增强):增强的逻辑,称为增强,比如扩展日志功能,这个功能称为增强 重点
Pointcut(切入点):在类里面可以有很多的方法被增强,比如实际操作中,只是增强了类里面的add方法和update方法,实际增强的方法称为切入点 重点
Joinpoint(连接点):类里面可以被增强的方法,这里方法称为连接点
前置通知:在方法之前执行
后置通知:在方法之后执行
异常通知:在方法出现异常时执行
最终通知:在后置之后执行
环绕通知:在方法之前和之后执行
(Aspect)切面:把增强应用到具体方法上面的的过程称为切面 重点
Target(目标对象):增强方法所在的类称为目标对象
关于@AspectJ的简单介绍
官方
- AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵循Java字节编码规范的Class为文件。
- AspectJ是一个基于Java语言的AOP框架
- Spring2.0以后增加了对AspectJ切点表达式的支持
- @AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
- 新版本Spring框架,建议使用AspectJ方式来开发AOP
总结
- 在Spring中进行AOP操作是使用AspectJ实现的
- AspectJ不是Spring的一部分,它是一个独立的面向切面的框架,通常和Spring配合使用来进行AOP操作
- Spring2.0以后增加了对AspectJ的支持
关于execution表达式
//常用表达式
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
示例:
- execution(* com.xianxian86.service.Book.*(..))
- execution(* com.xianxian86.service.Book.add(..))
- execution(* * . *(..))
- 匹配所有save开头的方法,execution(* save*(..))
Spring的AOP操作
AOP操作准备
导入Jar包,这里我使用Maven
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!--spring aop 支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!--aspectj 支持-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<!--junit 单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
</dependencies>
创建applicationContext.xml,并引入约束
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
AspectJ的AOP操作
xml方式
1、创建需要扩展功能的类及方法
public class Book {
/**
* 切入点
*/
public void add(){
System.out.println("方法执行了");
}
}
2、创建增强(通知)类及方法
增强 / 通知 :增强的逻辑,称为增强,比如扩展日志功能,这个功能称为增强
public class Advice {
/**
* 前置增强
*/
public void beFore(){
System.out.println("方法之前执行");
}
}
3、编写xml配置文件
<!--1、配置bean-->
<bean id="advice" class="com.xianxian86.aop.Advice"/>
<bean id="book" class="com.xianxian86.service.Book"/>
<!--1、配置aop-->
<aop:config>
<!--配置切入点:实际被增强的方法-->
<aop:pointcut id="pointcut"
expression="execution(* com.xianxian86.service.Book.*(..))"/>
<!--配置切面:把增强应用到切入点的过程-->
<aop:aspect ref="advice">
<!--配置前置通知(before):在方法之前执行 -->
<aop:before method="beFore" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
查看执行结果
十一月 02, 2020 8:53:07 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@51016012: startup date [Mon Nov 02 20:53:07 CST 2020]; root of context hierarchy
十一月 02, 2020 8:53:07 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
方法之前执行
方法执行了
Process finished with exit code 0
示例:环绕通知
1、需要更改Advice类和xml部分配置,其余操作不变
public class Advice {
public void aRound(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("方法之前执行");
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("方法之后执行");
}
}
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.xianxian86.service.Book.*(..))"/>
<aop:aspect ref="advice">
<aop:around method="aRound" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
<!-- 被更改的标签 -->
<!-- <aop:around method="aRound" pointcut-ref="pointcut"/> -->
查看执行结果
十一月 05, 2020 9:30:03 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@51016012: startup date [Thu Nov 05 21:30:03 CST 2020]; root of context hierarchy
十一月 05, 2020 9:30:03 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
方法之前执行
方法执行了
方法之后执行
Process finished with exit code 0
注解方式
1、开启aop注解支持
<!--开启aop操作-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2、使用注解配置AOP
/*
@Aspect 表示在该类中配置切面
切面:将增强应用到切入点的过程
*/
@Aspect
public class Advice {
/*
@Before
1、前置增强注解
2、value中配置需要被增强的方法(切入点)
*/
@Before(value = "execution(* com.xianxian86.service.Book.*(..))")
public void beFore(){
System.out.println("方法之前执行");
}
}
查看执行结果
十一月 05, 2020 9:17:39 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@51016012: startup date [Thu Nov 05 21:17:39 CST 2020]; root of context hierarchy
十一月 05, 2020 9:17:39 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
方法之前执行
方法执行了
Process finished with exit code 0