目录
[(1) 核心思想](#(1) 核心思想)
[(1) spring体系结构](#(1) spring体系结构)
[(2) spring框架模块](#(2) spring框架模块)
[(3) spring环境搭建](#(3) spring环境搭建)
[(4) IOC(Inversion of Control,中文释义:控制反转)](#(4) IOC(Inversion of Control,中文释义:控制反转))
[(5) AOP(中文释义:面向切面编程)](#(5) AOP(中文释义:面向切面编程))
(1)将类注入,SpringIoC容器(xml配置,注解实现)
[4.1 set注入基本类型和String](#4.1 set注入基本类型和String)
[4.2 set注入JavaBean对象(DI三层调用)](#4.2 set注入JavaBean对象(DI三层调用))
[4.3 set注入复杂类型](#4.3 set注入复杂类型)
[4.4 构造注入基本类型与String](#4.4 构造注入基本类型与String)
[4.5 构造注入 JavaBean对象(三层调用)](#4.5 构造注入 JavaBean对象(三层调用))
[五、spring 的配置](#五、spring 的配置)
[spring2.5后 ==xml+annotation](#spring2.5后 ==xml+annotation)
[spring3.0后 ==annotation+JavaConfig](#spring3.0后 ==annotation+JavaConfig)
[1、Spring 遵循的核心设计原则](#1、Spring 遵循的核心设计原则)
[(1). 依赖注入原则(Dependency Injection, DI)](#(1). 依赖注入原则(Dependency Injection, DI))
[(2). 控制反转原则(Inversion of Control, IoC)](#(2). 控制反转原则(Inversion of Control, IoC))
[(3). 面向接口编程原则](#(3). 面向接口编程原则)
[(4). 单一职责原则(Single Responsibility Principle)](#(4). 单一职责原则(Single Responsibility Principle))
[(5). 开闭原则(Open-Closed Principle)](#(5). 开闭原则(Open-Closed Principle))
[(6). 里氏替换原则(Liskov Substitution Principle)](#(6). 里氏替换原则(Liskov Substitution Principle))
[(7). 迪米特法则(Law of Demeter)](#(7). 迪米特法则(Law of Demeter))
[2、Spring 中常用的设计模式](#2、Spring 中常用的设计模式)
[(1). 工厂模式(Factory Pattern)](#(1). 工厂模式(Factory Pattern))
[(2). 单例模式(Singleton Pattern)](#(2). 单例模式(Singleton Pattern))
[(3). 模板方法模式(Template Method Pattern)](#(3). 模板方法模式(Template Method Pattern))
[(4). 代理模式(Proxy Pattern)](#(4). 代理模式(Proxy Pattern))
[七、Spring AOP](#七、Spring AOP)
[2、Spring AOP的实现](#2、Spring AOP的实现)
[(1).AOP连接点(Join point)](#(1).AOP连接点(Join point))
一、Spring
(1) 核心思想
Spring是一个轻量级、开源的Java企业级应用(指的是大规模、性能和安全要求高、业务复杂、灵活多变的大型WEB应用程序)开发框架,核心价值是通过依赖注入(DI)和面向切面编程(AOP)降低代码耦合度,简化开发流程,同时提供丰富的模块支持(如Web、数据访问、事务管理等)。也就是对象管理和功能增强的容器。
(1) spring体系结构

(2) spring框架模块
(1)Spring Core:Spring框架的最基础部分,提供DI特性。
(2)Spring Context:Spring上下文,提供Bean容器的集合。
(3)Spring AOP:基于Spring Core的符合规范的切面编程的实现。
(4)Spring JDBC:提供了JDBC的抽象层,简化了JDBC编码。
(5)Spring ORM:对于主流ORM框架(Hibernate、Toplink等)进行集成。
(6)Spring Web:为Spring在Web应用程序中的使用提供了支持。
(3) spring环境搭建
1.坐标(依赖)
2.主配置文件(beans.xml)
(4) IOC(Inversion of Control,中文释义:控制反转)
将对象的创建、依赖管理等"控制权"从代码中转移到Spring容器,开发者无需手动new对象,而是由容器统一创建和注入,极大降低耦合。
(5) AOP(中文释义:面向切面编程)
将日志、事务、权限校验等"通用功能"从业务代码中剥离,单独定义为"切面",在不修改业务代码的前提下,通过配置将通用功能织入到指定业务流程中,提升代码复用性。
二、SpringIOC的使用
由Spring框架根据配置文件或注解等方式,创建bean对象并管理各个bean对象之间的依赖关系,使对象之间形成松散耦合的关系,实现解耦。
控制:指的是对象创建(实例化、管理)的权利。
反转:控制权交给外部环境(Spring框架,IoC容器)。
1.使用步骤
(1)将类注入,SpringIoC容器(xml配置,注解实现)
java
<bean id="唯一标识" class="实现类的完全限定名称"></bean>
(2)加载spring主配置文件获取容器对象
实现类:
ClassPathXmlApplicationContext:通过加载配置文件的相对路径获取容器对象。 FileSystemXmlApplicationContext:通过加载配置文件的绝对路径获取容器对象。 AnnotationConfigApplicationContext:加载配置类。
接口:
ApplicationContext(子接口)
BeanFactory(父接口)
三、SpringDI
1.概念
DI(Dependecy Inject,中文释义:依赖注入) 是对IOC概念的不同角度的描述,是指应用程序在运行时,每一个bean对象都依赖IOC容器注入当前bean对象所需要的另外一个bean对象。
2.作用
胶水,帮助springIOC容器,把有依赖关系的javaBean对象粘合在一起。
3.实现步骤
(1)提供属性方法提供set方法。
(2)配置标签set注入:<property 属性名="属性值"></property>
4.SpringDI
实现方式:
(1)set注入 (2)构造注入 (3)属性注入 (4)注解注入
数据类型:
(1)基本类型与String
(2)JavaBean对象注入(三层调用)
(3)复杂类型(构造注入不支持 )
4.1 set注入基本类型和String
java
//teacher实体类
public class Teacher {
private String tname;
private int tage;
private String tsex;
//省略getter,setter、toString方法
}
java
//注入到xml文件中
<bean id="teacher" class="com.ape.pojo.Teacher">
<property name="tname" value="王老师"></property>
<property name="tage" value="30"></property>
<property name="tsex" value="男"></property>
</bean>
//属性:name==>属性名、value==>属性值、ref==>属性值的引用。
java
//测试类
public class Test03 {
public static void main(String[] args) {
//加载相对路径
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans.xml");
//通过Spring创建对象并加载XML文件
Teacher teacher=(Teacher) applicationContext.getBean("teacher");
System.out.println(teacher);
}
4.2 set注入JavaBean对象(DI三层调用)
java
//dao层接口与实现类
//分开写的
public interface IUserDao {
public void save();
}
public class UserDaoImp implements IUserDao{
@Override
public void save() {
System.out.println("===dao的新增方法===");
}
}
java
//service层接口与实现类
public interface IUserService {
public void save();
}
public class UserServiceImp implements IUserService{
IUserDao dao;
//set注入
public void setDao(IUserDao dao) {
this.dao = dao;
}
@Override
public void save() {
System.out.println("===service的新增方法===");
dao.save();
}
java
//controller层接口与实现类
public interface IUserController {
public void save();
}
public class UserControllerImp implements IUserController {
IUserService service;
//set注入
public void setService(IUserService service){
this.service=service;
}
@Override
public void save() {
System.out.println("===controller的新增方法===");
service.save();
}
}
java
//beans.xml
// <!--注入系统时间类-->
// <bean id="date" class="java.util.Date"></bean>
<bean id="daos" class="com.ape.dao.UserDaoImp"></bean>
<bean id="services" class="com.ape.service.UserServiceImp">
<property name="dao" ref="daos"></property>
</bean>
<bean id="controllers" class="com.ape.controller.UserControllerImp">
<property name="service" ref="services"></property>
</bean>
java
//测试类
public class Test02 {
public static void main(String[] args) {
//1.加载spring主配置文件,获取核心对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IUserController controllers= (IUserController) applicationContext.getBean("controllers");
controllers.save();
4.3 set注入复杂类型
java
//实体类
public class Student {
private String[] myArray;
private List myList;
private Set mySet;
private Map myMap;
private Properties myProperties;
//省略getter、setter、toString方法
}
java
//beans.xml
<bean id="student" class="com.ape.pojo.Student">
<property name="myArray">
<array>
<value>英雄联盟</value>
<value>王者荣耀</value>
<value>三角洲</value>
<value>CS1.5</value>
<value>魔兽争霸</value>
</array>
</property>
<property name="myList">
<list>
<value>字节跳动</value>
<value>阿里巴巴</value>
<value>小米</value>
<value>猿究院</value>
<value>腾讯</value>
</list>
</property>
<property name="mySet">
<set>
<value>朴彩英</value>
<value>金智秀</value>
<value>金珍妮</value>
<value>权志龙</value>
<value>Lisa</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="泰国" value="曼谷"></entry>
<entry key="中国" value="北京"></entry>
<entry key="缅甸" value="内比都"></entry>
<entry key="越南" value="河内"></entry>
<entry key="老挝" value="万象"></entry>
<entry key="新加坡" value="新加坡"></entry>
<entry key="马来西亚" value="吉隆坡"></entry>
</map>
</property>
<property name="myProperties">
<props>
<prop key="肉夹馍">10</prop>
<prop key="凉皮">7</prop>
<prop key="冰峰">2</prop>
<prop key="柳巷面">19</prop>
<prop key="一家星月楼">30</prop>
</props>
</property>
</bean>
java
//测试类
public class Test03 {
public static void main(String[] args) {
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans.xml");
Student student=(Student) applicationContext.getBean("student");
System.out.println(student);
4.4 构造注入基本类型与String
java
//实体类
public class Singer {
private String sname;
private int sage;
private String stype;
public Singer() {
}
public Singer(String sname, int sage, String stype) {
this.sname = sname;
this.sage = sage;
this.stype = stype;
}
@Override
public String toString() {
return "Singer{" +
"sname='" + sname + '\'' +
", sage=" + sage +
", stype='" + stype + '\'' +
'}';
}
}
java
//beans.xml
<!--基本类型与String-->
// 三种调用方式
<bean id="singer1" class="com.ape.pojo.Singer">
<constructor-arg name="sname" value="陈之默"></constructor-arg>
<constructor-arg name="sage" value="25"></constructor-arg>
<constructor-arg name="stype" value="RB"></constructor-arg>
</bean>
<bean id="singer2" class="com.ape.pojo.Singer">
<constructor-arg type="java.lang.String" value="汪苏泷"></constructor-arg>
<constructor-arg type="int" value="35"></constructor-arg>
<constructor-arg type="java.lang.String" value="RB"></constructor-arg>
</bean>
<bean id="singer3" class="com.ape.pojo.Singer">
<constructor-arg index="0" value="任贤齐"></constructor-arg>
<constructor-arg index="1" value="50"></constructor-arg>
<constructor-arg index="2" value="RB"></constructor-arg>
</bean>
java
//测试类
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans1.xml");
Singer singer1=(Singer)applicationContext.getBean("singer1");
Singer singer2=(Singer)applicationContext.getBean("singer2");
Singer singer3=(Singer)applicationContext.getBean("singer3");
System.out.println(singer1);
System.out.println(singer2);
System.out.println(singer3);
4.5 构造注入 JavaBean对象(三层调用)
java
//UserServiceImp类
//dao类不变
IUserDao dao;
//构造注入
public UserServiceImp() {
}
public UserServiceImp(IUserDao dao) {
this.dao = dao;
}
java
//UserControllerImp类
IUserService service;
//构造注入
public UserControllerImp() {
}
public UserControllerImp(IUserService service) {
this.service = service;
}
java
//beans1.xml
<!--javaBean对象-->
<bean id="daos1" class="com.ape.dao.UserDaoImp"></bean>
<bean id="service1" class="com.ape.service.UserServiceImp">
<constructor-arg name="dao" ref="daos1"></constructor-arg>
</bean>
<bean id="controller1" class="com.ape.controller.UserControllerImp">
<constructor-arg name="service" ref="service1"></constructor-arg>
</bean>
java
//测试类
public class Test05 {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans1.xml");
IUserController controller=(IUserController)applicationContext.getBean("controller1");
controller.save();
}
}
四、SpringIOC容器:对Bean的管理
1.bean的创建
(1)通过反射调用类的无参构造方法(默认)
java
//实体类
public class Singers {
public Singers() {
System.out.println("===执行Singers的无参构造方法===");
}
}
java
//BeanFactory工厂
public class BeanFactory {
//声明成员变量
static Properties pro=null;
//编写静态块做初始化操作
static {
try {
//1.实例化属性对象
pro=new Properties();
//2.加载静态资源文件
InputStream fis=BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties");
pro.load(fis);
} catch (IOException e) {
e.printStackTrace();
}
}
//帮助创建对象
public static Object getBean(String key){
//1.根据beanName在属性文件中获取对应value值
String value=pro.getProperty(key);
//2.通过反射实例化对象
Object obj=null;
try {
obj=Class.forName(value).newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return obj;
}
}
java
//beans2.xml
<bean id="singers" class="com.ape.pojo.Singers"></bean>
(2)通过指定的工厂,创建bean对象
java
//SingersFactory普通工厂
public class SingersFactory {
public Singers createSingers()
{
System.out.println("===执行SingersFactory工厂方法===");
return new Singers();
}
}
java
//beans2.xml
<bean id="singers" class="com.ape.pojo.Singers" factory-bean="factory" factory-method="createSingers"></bean>
<bean id="factory" class="com.ape.factory.SingersFactory"></bean>
(3)通过指定的静态工厂,创建bean对象
java
//SingersStaticFactory静态工厂
public class SingersStaticFactory {
//创建对象
public static Singers createSingers()
{
System.out.println("===执行SingersStaticFactory静态工厂方法===");
return new Singers();
}
}
java
//beans2.xml
<bean id="singers" class="com.ape.factory.SingersStaticFactory" factory-method="createSingers"></bean>
java
//测试类
public class Test06 {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans2.xml");
Singers singers=(Singers)applicationContext.getBean("singers");
System.out.println(singers);
2.bean的作用域
含义:bean的创建方式
语法:<bean scope="属性值"></bean>
属性值: singleton单例(默认)、 prototype多例、 request请求、session会话。
java
//eg:将其设为多例,每调用一次就会创建一次对象
<bean id="students" class="com.ape.pojo.Students" scope="prototype"></bean>
3.bean的生命周期

1.实例化
Spring容器在进行实例化时,会将xml或注解配置的信息封装成一个BeanDefinition对象,所有的BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架在对该Map进行遍历,通过Spring的后处理器(Bean工厂后处理器:BeanFactoryPostProcessor有两个子接口(BeanFactoryPostProcessor(注册和修改)/
BeanDefinitionRegistryPostProcessor(注册))、允许我们介入到Bean的整个实例化的过程中来,以达到动态注册BeanDefinition、动态修改BeanDefinition以及动态修改Bean的作用,最后使用反射创建Bean实例对象,生成一个半成品的对象。
2.初始化
将半成品的对象注入对象依赖的属性值、若实现了Aware的相关接口,就执行一些Aware接口的方法、若实现了BeanPostProcess接口,就执行Bean后处理器(BeanPostProcessor)的前置处理(postProcessBeforeInitialization方法),接下来若Bean实现了InitializingBean接口,就调用其afterPropertiesSet()方法,若通过@PostConstruct注解指定了方法,或类中自定义了初始化方法并在XML中配置了init-method,就执行对应方法。最后执行后置处理(postProcessAfterInitialization方法),执行完成后,完整的Bean对象就会被放在singletonObjects中,以供后续使用。
3.操作使用
调用getBean()方法获取Bean对象
4.销毁
调用ClassPathXmlApplicationContext的close()方法触发销毁,若Bean实现了DisposableBean接口,调用其destroy()方法。 若通过@PreDestroy注解指定了方法,或自定义了销毁方法并XML中配置了destroy-method,就执行对应方法。
作用:释放资源(如关闭连接、清理缓存)。
1.实例化
创建对象(无参构造)
2.初始化
2.1接口初始化(实现InitializingBean)
2.2属性初始化(自己创建方法)
3.操作使用
4.销毁
4.1接口销毁了(实现DisposableBean)
4.2属性销毁了(自己创建方法)
销毁前,在测试类中,调用ClassPathXmlApplicationContext实现类的close()方法,才会执行到销毁方法。
java
//Teachers类
public class Teachers implements InitializingBean, DisposableBean {
//实例化
public Teachers(){
System.out.println("====>生命周期:实例化");
}
//初始化(接口)
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("====>生命周期:初始化1(接口)");
}
//销毁(接口)
@Override
public void destroy() throws Exception {
System.out.println("====>生命周期:销毁1(接口)");
}
//初始化(属性)
public void doInit(){
System.out.println("====>生命周期:初始化2(属性)");
}
//销毁(属性)
public void doDestroy(){
System.out.println("====>生命周期:销毁2(属性)");
}
}
java
//xml
<bean id="teachers" class="com.ape.pojo.Teachers" init-method="doInit" destroy-method="doDestroy"></bean>
java
//测试类
public class Test07 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans2.xml");
Teachers teachers = (Teachers)applicationContext.getBean("teachers");
System.out.println(teachers);
applicationContext.close(); //子类独有的方法
}
}
五、spring 的配置
(1)spring2.5前 ==xml
(2)spring2.5后 ==xml+annotation
(3)spring3.0后 ==annotation+JavaConfig配置类
spring2.5后 ==xml+annotation
目的优化一下代码: <bean id="" class="" init-method="" destroy-method="" scope="" autowire=""> <property></property> <constructor-arg></constructor-arg> </bean>
注解:
1.注入类
替换:<bean id="" class=""></bean>
位置:类
语法:@Component(value="注入容器中的id,如果省略id则为类名且首字母小写,value属性名称可以省略")
举例: <bean id="user" class="com.apesource.包.User"></bean> || 等价于 ||
@Component
Class User{}
注意: 不能单独用,配合扫描使用<context:component-scan base-package=""> </context:component-scan>
@Repository===== 注入数据访问层
@Service======= 注入业务层
@Controller==== 注入控制层
以上三个注解与@Component功能语法一致
2.注入数据
@Value
含义:注入基本数据与String
替换:<property></property>
修饰:成员变量
语法:@Value("数据内容") @Value("${动态获取}")
注意: 不能单独使用,配合加载配置文件标签 <context:property-placeholder location="classpath:message.properties"></context:property-placeholder>
@Autowired
语法:@Autowired(required="true-默认、false、是否必须进行装配")
修饰:成员变量
含义:注入javaBean
注意:
1.默认是按照类型装配,如果容器中有多个类型,则会自动切换为名称装配
2.默认是按照类型装配,如果容器中有多个类型,则会自动切换为名称装配,若名称也没有与之对应的则会报异常 NoUniqueBeanDefinitionException
3.默认是按照类型装配 ,如果容器中没有一个类可以与之匹配,则会报异常NoSuchBeanDefinitionException
3.其他注解
@Primary
含义:首选项,当类型冲突的情况下,此注解修饰的类被列为首选(备胎扶正)
修饰:类
注意:不能单独使用,必须与@Component....联合使用
@Qualifier(value="名称") spring提供
含义:按照名称装配
修饰:成员变量
注意:不能单独使用,必须与@Autowired联合使用
@Resource(name="名称") jdk提供
含义:按照名称装配
修饰:成员变量
注意:单独使用
@Scope
含义:配置类的作用域
修饰:类
注意:不能单独使用,必须与@Component....联合使用
@Scope("prototype") @Scope("singleton") @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@PostConstruct:初始化,替换init-method
@PreDestroy:销毁,替换destory-method
spring3.0后 ==annotation+JavaConfig
配置类 此类充当配置类,替代applicationContext.xml文件
@Configuration
作用:指定当前类是一个配置类
细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
@ComponentScan
作用:用于通过注解指定spring在创建容器其时要扫描的包
替换:<context:component-scan base-package=""></context:component-scan>
@PropertySource
作用:用于指定properties文件的位置
替换:<context:property-placeholder location=""></context:property-placeholder>
六、Spring遵循的原则以及设计模式
1、Spring 遵循的核心设计原则
(1). 依赖注入原则(Dependency Injection, DI)
核心思想:组件不主动创建依赖对象,而是通过外部容器(Spring)注入依赖,降低组件间耦合。
体现 :通过@Autowired
、构造器注入等方式,让对象的依赖由容器管理,而非自身硬编码。
(2). 控制反转原则(Inversion of Control, IoC)
核心思想:将对象的创建、管理权从业务代码转移到 Spring 容器,反转了传统的 "主动创建依赖" 的流程。
体现:容器负责 Bean 的生命周期(实例化、注入、销毁),开发者专注于业务逻辑。
(3). 面向接口编程原则
核心思想:依赖抽象(接口)而非具体实现,提高代码的可替换性和扩展性。
体现 :Spring 中的BeanFactory
与ApplicationContext
、Resource
接口及其实现类等,均通过接口定义规范,具体实现可灵活替换。
(4). 单一职责原则(Single Responsibility Principle)
核心思想:一个类只负责一项职责,降低耦合度和维护成本。
体现 :BeanFactory
专注于 Bean 的创建,ApplicationContext
扩展上下文功能,TransactionManager
专注于事务管理等。
(5). 开闭原则(Open-Closed Principle)
核心思想:对扩展开放,对修改关闭,通过抽象和接口实现灵活扩展。
体现 :通过BeanPostProcessor
、FactoryBean
等扩展点,无需修改 Spring 源码即可增强功能(如自定义 Bean 初始化逻辑)。
(6). 里氏替换原则(Liskov Substitution Principle)
核心思想:子类可替换父类且不改变原有功能逻辑。
体现 :Spring 中各种接口的实现类(如ArrayList
实现List
)可无缝替换,不影响依赖该接口的代码。
(7). 迪米特法则(Law of Demeter)
核心思想:一个对象应尽可能少地了解其他对象,降低耦合。
体现:通过 Spring 容器作为中间层,组件无需直接交互,而是通过容器间接获取依赖,减少彼此的了解。
2、Spring 中常用的设计模式
(1). 工厂模式(Factory Pattern)
应用:BeanFactory
和ApplicationContext
是典型的工厂模式实现,负责创建和管理 Bean 对象。
示例:BeanFactory.getBean(String name)
通过名称获取 Bean,隐藏了对象创建的细节。
(2). 单例模式(Singleton Pattern)
应用:Spring 默认的 Bean 作用域为单例(singleton
),容器中只会创建一个实例并复用。
实现:通过singletonObjects
缓存单例 Bean,保证全局唯一(非绝对线程安全,需用户自行处理并发)。
(3). 模板方法模式(Template Method Pattern)
应用:定义算法骨架,将可变步骤延迟到子类实现,减少重复代码。
示例:JdbcTemplate
封装了 JDBC 的固定流程(连接、关闭资源),用户只需提供SQL
和结果映射逻辑。
(4). 代理模式(Proxy Pattern)
应用:AOP(面向切面编程)的核心实现,通过动态代理增强目标方法(如事务、日志、权限控制)。
类型:JDK 动态代理:基于接口的代理(如Proxy
类)。
CGLIB代理:基于类的继承代理(适用于无接口的类)。
七、Spring AOP
1、AOP概念及作用
(1).概念
AOP(Aspect-Oriented Programming: 面向切面编程):将那些与业务无关,却为业务模块所共同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽取成一个可重用的模块,这个模块被命名为"切面"(Aspect),便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
(2).作用
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(提高代码复用率以及解耦)
2、Spring AOP的实现
Spring AOP 基于动态代理实现:
(1).如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
(2).如果被代理的对象,没有实现某个接口,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是MethodInterceptor接口和Enhancer类);
3、AOP通知
AOP将抽取出来的共性功能称为通知;通知类型:以通知在上下文中的具体位置作为划分。
解释:通知就是需要增强的方法的方法内容以及执行位置的结合。
- 前置通知(Before)--执行前
- 返回通知(After-returning)--执行完成后
- 异常通知(After-throwing)--执行有错误
- 后置通知(After)--不管如何都要执行的
- 环绕通知(Around)--替换上面四个的
4、AOP配置
(1).AOP连接点(Join point)
AOP将所有的方法都视为连接点,不管是接口里面的抽象方法,还是实现类里面的重写方法,都是连接点。
解释:具备添加通知能力的方法位置,就是连接点,也就是所有类的所有方法。
(2).AOP切点(Pointcut)
AOP将可能被抽取共性功能的方法称为切入点。切入点是连接点的子集。
解释:成功添加了通知的方法位置,就是切点。
(3).AOP目标对象(Target)
就是挖掉功能的方法对应的类生的对象,这种对象是无法直接完成最终工作的。
解释:被代理对象,就是目标对象。
(4).AOP织入(Weaving)
就是将挖掉的功能回填的动态过程
解释:将通知添加到切点的过程ing,就是织入
(5).AOP切面:切点+通知
(6).SpringAOP+AspectJ实现步骤
1.坐标
2.配置
5、切点表达式配置语法
execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
eg:execution(public void com.apesource.service.ServiceImp.findAll())
(1).修饰符可以省略代表任意
execution(返回值 包名称.类名称.方法名称(参数列表))
(2).返回值可以使用"*"代表任意
execution(* 包名称.类名称.方法名称(参数列表))
(3).包名可以使用"*"代表任意名称
execution(* *.*.*.类名称.方法名称(参数列表))
eg:execution(void *.*.*.ServiceImp.findAll())
(4).包名可以使用".."代表任意个数
execution(* *...类名称.方法名称(参数列表))
eg:execution(void *..ServiceImp.findAll())
(5).类名与方法名可以使用"*"代表任意
execution(* *...*.*(参数列表))
(6).参数列表可以使用".."代表任意个数任意类型
execution(* *...*.*(..))
如果有参数
int======>int
String===>java.lang.String
java
public interface IAccountService {
//新增
public void insert(int i);
//修改
public void update();
//删除
public int delete();
}
java
//注解 @Service
public class AccountServiceImp implements IAccountService {
public void insert(int i) {
System.out.println("业务层的新增方法:"+i);
}
public void update() {
System.out.println("业务层的修改方法");
// int a=10/0;
}
public int delete() {
System.out.println("业务层的删除方法");
return 0;
}
}
java
// @Component
// @Aspect
public class Logger {
// @Pointcut("execution(* com.apesource.service.*.*(..))")
// public void dian(){
// }
//@Before("dian()")
public void beforeLogger(){
System.out.println("前置==日志类logger中调用printLogger方法进行日志记录");
}
//@AfterReturning("dian()")
public void returnLogger(){
System.out.println("返回==日志类logger中调用printLogger方法进行日志记录");
}
//@AfterThrowing
public void throwLogger(){
System.out.println("异常==日志类logger中调用printLogger方法进行日志记录");
}
//@After("dian()")
public void afterLogger(){
System.out.println("后置==日志类logger中调用printLogger方法进行日志记录");
}
//around替换上面的
//@Around("dian()")
// public Object aroundLogger(ProceedingJoinPoint pjp){
// Object obje=null;
// try {
// System.out.println("环绕通知==前置");
// Object[] args = pjp.getArgs();
// obje=pjp.proceed(args);
// System.out.println("环绕通知==返回");
// } catch (Throwable e) {
// System.out.println("环绕通知==异常");
// throw new RuntimeException(e);
// } finally {
// System.out.println("环绕通知==后置");
// }
// return obje;
// }
java
<!--xml-->
<!--注入业务层-->
<bean id="accountServiceImp" class="com.apesource.service.AccountServiceImp"></bean>
<!--注入日志记录层(通知)-->
<bean id="logger" class="com.apesource.util.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面 -->
<aop:aspect id="aopAspect" ref="logger">
<!--切点-->
<aop:pointcut id="dian" expression="execution(public * com.apesource.service.*.*(..))"/>
<!--通知-->
<aop:before method="beforeLogger" pointcut-ref="dian"></aop:before>
<aop:after-returning method="returnLogger" pointcut-ref="dian"></aop:after-returning>
<aop:after-throwing method="throwLogger" pointcut-ref="dian"></aop:after-throwing>
<aop:after method="afterLogger" pointcut-ref="dian"></aop:after>
// <aop:around method="aroundLogger" pointcut-ref="dian"></aop:around>
</aop:aspect>
</aop:config>
<!--注解-->
// <context:component-scan base-package="com.apesource"></context:component-scan>
<!-- 注解驱动-->
<!-- @EnableAspectJAutoProxy-->
// <aop:aspectj-autoproxy/>
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class Test01 {
@Autowired
public IAccountService service;
@Test
public void show1(){
service.update();
}
八、循环依赖
注入双向对象引用属性演示
含义:多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用。


解决方案:
Spring提供了三级缓存存储 完整Bean实例 和 半成品Bean实例 ,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map
java
public class DefaultSingletonBeanRegistry ... {
//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三
级缓存"
Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
注:将对象保存至三级缓存的时候,会包装成ObjectFactory对象录入,
未来通过此接口对应的get方法再次提取对象.
UserService和UserDao循环依赖的过程结合上述三级缓存描述一下
UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;
UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;
UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移 入二级缓存;
UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
UserService 注入UserDao;
UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓
存。
九、常用的Aware接口
Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接 触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了 ,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象 。
总结:处理器的作用,为Bean生命周期各个阶段提供扩展。
