初始Spring

目录

一、Spring

[(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(中文释义:面向切面编程))

二、SpringIOC的使用

1.使用步骤

(1)将类注入,SpringIoC容器(xml配置,注解实现)

(2)加载spring主配置文件获取容器对象

三、SpringDI

1.概念

2.作用

3.实现步骤

4.SpringDI

[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对象(三层调用))

四、SpringIOC容器:对Bean的管理

1.bean的创建

(1)通过反射调用类的无参构造方法(默认)

(2)通过指定的工厂,创建bean对象

(3)通过指定的静态工厂,创建bean对象

2.bean的作用域

3.bean的生命周期

1.实例化

2.初始化

3.操作使用

4.销毁

[五、spring 的配置](#五、spring 的配置)

[spring2.5后 ==xml+annotation](#spring2.5后 ==xml+annotation)

1.注入类

2.注入数据

3.其他注解

[spring3.0后 ==annotation+JavaConfig](#spring3.0后 ==annotation+JavaConfig)

六、Spring遵循的原则以及设计模式

[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)

1、AOP概念及作用

(1).概念

(2).作用

[2、Spring AOP的实现](#2、Spring AOP的实现)

3、AOP通知

4、AOP配置

[(1).AOP连接点(Join point)](#(1).AOP连接点(Join point))

(2).AOP切点(Pointcut)

(3).AOP目标对象(Target)

(4).AOP织入(Weaving)

(5).AOP切面:切点+通知

(6).SpringAOP+AspectJ实现步骤

5、切点表达式配置语法

(1).修饰符可以省略代表任意

(2).返回值可以使用"*"代表任意

(3).包名可以使用"*"代表任意名称

(4).包名可以使用".."代表任意个数

(5).类名与方法名可以使用"*"代表任意

(6).参数列表可以使用".."代表任意个数任意类型

八、循环依赖

九、常用的Aware接口


一、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 中的BeanFactoryApplicationContextResource接口及其实现类等,均通过接口定义规范,具体实现可灵活替换。

(4). 单一职责原则(Single Responsibility Principle)

核心思想:一个类只负责一项职责,降低耦合度和维护成本。

体现BeanFactory专注于 Bean 的创建,ApplicationContext扩展上下文功能,TransactionManager专注于事务管理等。

(5). 开闭原则(Open-Closed Principle)

核心思想:对扩展开放,对修改关闭,通过抽象和接口实现灵活扩展。

体现 :通过BeanPostProcessorFactoryBean等扩展点,无需修改 Spring 源码即可增强功能(如自定义 Bean 初始化逻辑)。

(6). 里氏替换原则(Liskov Substitution Principle)

核心思想:子类可替换父类且不改变原有功能逻辑。

体现 :Spring 中各种接口的实现类(如ArrayList实现List)可无缝替换,不影响依赖该接口的代码。

(7). 迪米特法则(Law of Demeter)

核心思想:一个对象应尽可能少地了解其他对象,降低耦合。

体现:通过 Spring 容器作为中间层,组件无需直接交互,而是通过容器间接获取依赖,减少彼此的了解。

2、Spring 中常用的设计模式

(1). 工厂模式(Factory Pattern)

应用:BeanFactoryApplicationContext是典型的工厂模式实现,负责创建和管理 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生命周期各个阶段提供扩展。

相关推荐
葡萄城技术团队3 小时前
突破Excel局限!SpreadJS让电子表格“活”起来
java·数据库·excel
J总裁的小芒果3 小时前
SQL Server 报错 当 IDENTITY_INSERT 设置为 OFF 时,不能为表 ‘ORDER_BTN‘ 中的标识列插入显式值
数据库
吹个口哨写代码3 小时前
处理文本编辑器存的json格式报错问题,对编辑器存的字段进行转换处理,再通过json返回
java·编辑器·json
神的孩子都在歌唱3 小时前
PostgreSQL 向量检索方式(pgvector)
数据库·人工智能·postgresql
阿挥的编程日记3 小时前
基于SpringBoot的影评管理系统
java·spring boot·后端
Chloeis Syntax3 小时前
栈和队列笔记2025-10-12
java·数据结构·笔记·
java坤坤4 小时前
Spring Boot 集成 SpringDoc OpenAPI(Swagger)实战:从配置到接口文档落地
java·spring boot·后端
Uluoyu4 小时前
word、pdf文档内容提取工具类
java·pdf·word