Spring

Spring是一个企业级的开源框架,它通过IOC和AOP技术实现组件管理与解耦。IOC(控制反转)将对象创建权交给容器,AOP(面向切面编程)用于处理系统中重复的通用功能。Spring提供了基于XML和注解两种使用方式,通过配置文件或注解创建并管理对象。依赖注入允许对象间的依赖关系由Spring容器管理,降低了耦合度。AOP则允许在不修改源码的情况下,将通用功能插入到系统执行的特定位置,提高代码复用性和维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Spring

一、 什么是Spring

  1. Spring是一个优秀的开源的企业级框架。

  2. Spring和其他框架不同,其他框架大多是专注于某一领域的框架(如MyBatis专注于持久层的框架),而Spring是一个包罗万象的框架。

  3. Spring是一个管理框架的框架,尽管Spring包罗万象,但它又不具体做任何事情,Spring奉行一个“不重复制造轮子”的原则,如已经存在了MyBatis这样的持久化框架,Spring就不会重复的开发一个持久化框架,而是使用MyBatis等持久化框架,实现持久化功能,Spring是通过集成其他框架实现各领域的管理和协作。

  4. Spring通过管理和整合软件开发中使用到的各种组件和框架,实现各组件和框架的搭配组合使用,并让各组件和框架的使用更简洁、更方便,Spring在整合其他框架的过程中,将一些通用的功能、各组件间的依赖关系自动管理起来,让开发者从这些繁琐重复的代码中解脱出来,从而实现“优雅编程”(开发者只需编写个性化和业务相关的代码),让开发变得更简单、更方便。

  5. Spring的作用:

(1) 对系统中的各个组件进行有效的管理让其能协调工作

(2) 使各个组件之间的耦合度降低,提高各个组件的可维护性(高内聚低耦合)

  1. Spring中使用面向接口编程

  2. Spring提供两大核心技术,其他技术都是在这两项技术的基础上搭建起来的:IOC(***控制反转和AOP(***面向切面编程)

(1) IOC:称为控制反转,将对象的创建及对象间依赖关系的维护权由对象自身交给***外部容器***管理,这种管理权的转移我们称为控制反转,实现各组件间的解耦;IOC的实现依赖DI(依赖******注入)

(2) AOP:面向切面编程, 将系统中多处都要使用的通用功能,从各个部分分离出来,单独开发和维护,不再各个部分代码中调用。而是在系统运行时由外部容器将这些功能嵌入到各部分代码中。(过滤器、拦截器都属于面向切面思想)

  1. Spring体系结构

image-20210123120840276

二、 使用Spring框架

  1. Spring框架提供了两种使用方式:
(1) 基于XML实现

使用步骤:

  1. 在Maven中引入spring-context依赖包,此时Maven会将spring的相关包如core、aop、beans、expression包同步下载
<!-- spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>

2.在项目中resource文件夹下配置spring的核心配置文件(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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
        配置bean标签,将对象交给spring容器管理
        此时class指定的类的对象由spring容器来创建并管理
        id:对象名
    -->
    <bean id="userDao" class="com.jiazhong.spring.dao.impl.UserDaoImpl"/>

</beans>

3.使用spring容器创建并使用对象

/**
   * 启动spring环境并初始化spring容器
   * ClassPathXmlApplicationContext是ApplicationContext接口基于XML的一个实现类
   */
   ApplicationContext applicationContext = 
      new ClassPathXmlApplicationContext("applicationContext.xml");
   //从容器中获得对象,根据对象名获得
   UserDao userDao = (UserDao) applicationContext.getBean("userDao");
   userDao.addUser();
(2) 基于注解编程式实现
  1. 创建一个配置类,任意一个类,但要使用@Configuration

  2. 在配置类中定义方法,用于创建Bean对象,在方法上要加入@Bean注解,@Bean注解的作用,将方法的返回值对象交给spring进行管理,对象名默认为方法名,我们可以通过注解设置对象名

@Configuration//加入此注解后该就成了spring的一个配置类
public class ApplicationContextConfig {
    //该注解只能在配置类中的方法中使用,表示将方法的返回值交给spring进行管理的一个Bean对象
    //Bean注解默认的对象名为方法名,我们可以设置对象名@Bean("userDao")
    @Bean()
    public UserDao userDaoImpl(){
        return new UserDaoImpl();
    }
}
//使用时
public class Test1 {
    public static void main(String[] args) {
        //初始化Spring环境并指定核心配置类
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationContextConfig.class);
        UserDao userDao = (UserDao) applicationContext.getBean("userDao1");
        userDao.queryUser();
    }
}

Spring对象管理

(1) Spring管理对象的创建时机

a) 默认情况下,spring容器一创建,由spring管理的对象同步创建

b) 可以通过相关配置修改Spring受管对象的创建时机

c) 配置lazy属性可以让spring的受管对象进行懒加载创建(在使用时创建)

设置lazy的方式有两种:

​ 1.设置全局对象lazy(Spring的所有收管对象使用懒加载机制)

​ 在XML的beans标签中配置:

default-lazy-init=“true”:设置全局受管对象懒加载,当第一次使用该对象时才创建

​ 2.设置某个对象使用懒加载机制创建

​ 在bean标签中加入lazy-init=“true”

(默认情况下,spring容器管理的对象是单例的

受管对象的实例只有一个

我们可以通过相应的配置设置spring收管对象的实例

​ 通过在bean标签中配置scope="prototype"来设置对象每次使用都创建一个新对象**

​ Scope设置为prototype后容器启动时将不会创建类的对象,而是每次使用时创建该类的对象,此时对象并不在spring容器中存放)

(2 )对象初始化和销毁方法

基于XML配置中的init-method属性指定初始化方法(构造方法执行后自动调用),destory-method方法指定销毁方法(对象销毁前自动调用)

  1. Spring的依赖注入(DI)

在Spring中所有对象的创建及管理都由spring容器负责,如果一个对象中要使用其他由spring容器管理的对象时,就需要spring通过依赖注入将对象注入到使用的对象中;”简言之依赖注入指向对象的属性赋值”

(1) 基于XML的依赖注入

  1. Set注入:通过set方法注入依赖对象,为依赖对象提供set方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- default-lazy-init="true":设置全局延迟创建Bean对象-->
    <!--
        Spring默认情况下,在启动时会创建受管对象
        默认情况下,Spring的对象时单例的
        bean标签用于将类交给Spring进行管理
        name:设置对象名
   	    class:设置对象的类
        lazy-init:延迟初始化,当使用该对象Spring才创建该对象
        scope="prototype":设置Spring对象是单例存在还是每使用一次创建一个(singleton<单例>|prototype<非单例>)
     面试题:Spring中一个Bean设置scope属性的为"prototype",该对象是否(受Spring管理)存在于spirng容器中

    -->
    <bean name="userDao"
          class="com.jiazhong.dao.impl.UserDaoImpl"
          lazy-init="false"
          scope="singleton"
            init-method="init"
            destroy-method="destory"></bean>
   <!-- 当service对象需要userDao对象时-->           
  <bean name="userService" class="com.jiazhong.service.impl.UserServiceImpl">
        <!--
            向userService对象注入userDao对象
            property表示set注入,属性必须提供set方法
            ref:指定的是一个由spring受管的对象
            value:基本类型
        -->
        <property name="userDao" ref="userDao"></property>
           //基本类型注入
         <!-- <property name="name" value="小明"></property> 
           //集合类型注入
          <property name="myset">
            <set>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </set>
        </property>
        <property name="mymap">
            <map>
                <entry key="aaa" value="bbb"></entry>
                <entry key="bbb" value="ccc"></entry>
            </map>
        </property>
        <property name="myprops">
            <props>
                <prop key="aaa">aaa</prop>
                <prop key="bbb">bbb</prop>
            </props>
        </property>
        //构造器注入 
        <constructor-arg index="0" value="1"></constructor-arg>
        <constructor-arg index="1" value="小明"></constructor-arg>
        <constructor-arg index="2" >
                <list> 	
                	<value>1111</value>
                </list>
        </constructor-arg>
                -->
    </bean> 

Aop 面向切面

AOP(面向切面编程)全称Aspect Oriented Programming

AOP就是把系统中重复的代码抽取出来,单独开发 ,在系统需要时,使用动态代理技术,在不修改源码的基础上,将单独开发的功能通知织入(应用)到系统中的过程,完成完整的代码逻辑
优点:减少重复代码、提高开发效率、提高维护性
AOP相关术语:
1.Joinpoint(连接点):连接点是指那些被拦截到的点。在spring中这些点指的是方法,spring只支持方法类型的连接点。
指切面在系统中要应用的位置,spring中能够使用切面的位置为方法,所以连接指方法
2.Pointcut(切入点):指我们要对那些Joinpoint进行拦截的定义,spring中使用切入点表达式定义(切入点表达式)
简单理解,切入点是对连接点的描述,它将多个连接点进行概括的定义
3.Advice(通知):指拦截到joinpoint之后所要做的事情就是通知
通知:前置通知、后置通知、异常通知、最终通知、环绕通知
4.Target(目标对象):代理的目标对象
5.Weaving(织入):将通知应用到切入点的过程
6.Proxy(代理):代理对象
7.Aspect(切面):切入点和通知的总称
简单说AOP是,在系统执行某个方法时,在执行这个方法前或方法后去执行另一段程序(另一段程序就是AOP中的通知),而拦截这个方法的定义可以称为切入点

SpringAOP的使用步骤(基于注解):

​ 1.引入spring依赖包和aop植入依赖包AspectJ Weaver包
​ 2.创建切面类
​ 3.将切面类交个spring进行管理,使用@Component注解
​ 4.将切面类设置为一个切面,使用@Aspect注解
​ 5.编写切入点poincut,使用切入点表达式定义连接点(方法)。
​ Execution(表达式)
表达式写法:访问修饰符 返回类型 包名.包名.类名.方法名(参数列表)//指定那些方法做为切入点(拦截那些方法)
使用具体方法方式:void com.jiazhong.service.impl.UserServiceImpl.addUser()
使用通配符方式:* .*(…)
6.编写相关通知

/**
流程:
1.第一步
@Component//将切面类交给Spring管理
@Aspect//表示该类为一个切面类
@EnableAspectJAutoProxy//开启AOP的动态代理
2.第二🙅‍
定义切入点,使用切入点表达式定义要拦截的方法的连接点
 @Pointcut:该注解用于定义切入点表达式
3.第三步   
      @Before("myPointcut()") 	前置通知
      @AfterReturning("myPointcut()")后置通知
      @AfterThrowing("myPointcut()")异常通知
      @After("myPointcut()")
      
      /**
     * 环绕通知,它可以在方法调用前、后、异常中、最终执行
     * 在环绕通知内部必须主动调用目标方法
     * @param proceedingJoinPoint*/
    @Around("myPointcut()")  
*/
//---------------------------------------------------------
@Component//将切面类交给Spring管理
@Aspect//表示该类为一个切面类
@EnableAspectJAutoProxy//开启AOP的动态代理
public class MyAspect {
    /**
     * 定义切入点,使用切入点表达式定义要拦截的方法的连接点
     * @Pointcut:该注解用于定义切入点表达式
     * myPointcut():切入点的名字
     *
     * 切入点表达式:
     *      (1)void com.jiazhong.service.impl.UserServiceImpl.addUser():连接点是 void addUser()方法
     *      //拦截UserServiceImpl类中的所有方法,*表示任意,..表示任意参数
     *      (2)* com.jiazhong.service.impl.UserServiceImpl.*(..)
     *      //拦截impl包及其子包中的类的所有方法
     *      (3)* com.jiazhong.service.impl..*.*(..)
     *
     */
    
    //定义切点
    @Pointcut("execution(* com.jiazhong.service.impl.UserServiceImpl.*(..))")
    private void myPointcut(){}//声明切入点和方法的声明一样,但没有方法体

    /***
     * 定义通知
     *  1.前置通知:在目标方法调用前执行的通知
    @Before("myPointcut()")
    public void beforeAdvice(){
        System.out.println("执行前置通知...");
    }*/

    /**
     * 后置通知
    @AfterReturning("myPointcut()")
    public void afterReturnning(){
        System.out.println("执行后置通知...");
    }*/

    /**
     * 异常通知
    @AfterThrowing("myPointcut()")
    public void afterThrowing(){
        System.out.println("异常通知...");
    } */

    /***
     * 最终通知
    @After("myPointcut()")
    public void after(){
        System.out.println("最终通知...");
    }*/

    /**
     * 环绕通知,它可以在方法调用前、后、异常中、最终执行
     * 在环绕通知内部必须主动调用目标方法
     */
    @Around("myPointcut()")
    public Object round(ProceedingJoinPoint proceedingJoinPoint){
        try {
            //前置通知
            System.out.println("开始调用目标方法...");
            //获得目标方法签名
            Signature signature = proceedingJoinPoint.getSignature();
            System.out.println(signature.getName());
            Object obj = proceedingJoinPoint.proceed();//调用目标方法
            //后置通知
            System.out.println("目标方法调用结束...");
            return obj;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知....出现异常了");
        }finally {
            System.out.println("最终通知...");
        }
        return null;
    }
}

image-20210123120026604

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值