Spring总结

一.Spring Framework

1.什么是 Spring Framework

  1. spring 是一个开源应用框架,旨在降低应用程序开发的复杂度。
  2. 它是轻量级、松散耦合的。
  3. 它具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序开发提供了一个有凝聚力的框架。
  4. 它可以集成其他框架,如Structs、Hibernate、EJB 等,所以又称为框架的框架。

2. Spring Framework 的优点

  1. 非侵入式:使用Spring Framework开发项目时,其对项目本身的结构影响极小,用注解的方式对功能性组件进行标记不仅不会破坏结构,反而简化了开发。
  2. 控制反转(IOC):翻转资源获取方向,从自己主动new资源、向环境获取资源转变为环境将资源准备好并注入,我们直接使用。提到IOC必然会提到DI(依赖注入),DI是IOC的另一种表述方式,即组件以一些预先定义好的方式接受来自于容器的资源注入,它是IC的一种具体体现。
  3. 容器:SpringIOC是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化的管理,提程序员屏蔽了组件创建过程中的大量细节,极大地降低了使用门槛,大幅度提高了开发效率。
  4. 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用,zaisoring中可以使用XML和JAVA注解组合对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭
    建超大型复杂应用系统。
  5. 声明式:很多以前需要编写代码才能实现的功能,现在只需要声明需求即可由框架代为实现。
  6. 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且 Spring 旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在 Spring Framework 的基础上全部使用 Spring 来实现。

3. Spring Framework 有哪些不同的功能?

  1. 轻量级: Spring 在代码量和透明度方面都很轻便, 基本的版本大约 2MB。
  2. 控制反转(IOC): Spring 通过控制反转实现了松散耦合。
  3. 面向切面编程(AOP): 可以将应用业务逻辑和系统服务分离,以实现高内聚。
  4. 容器: Spring 负责创建和管理对象(Bean)的生命周期和配置。
  5. MVC框架: 对 web 应用提供了高度可配置性,其他框架的集成也十分方便。
  6. 事务管理 - 提供了用于事务管理的通用抽象层。Spring 的事务支持也可用于容器较少的环境。
  7. 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。

4. Spring Framework 中有多少个模块,它们分别是什么?

  1. Spring Core:Core封装包是框架的最基础部分,提供IOC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。

  2. Spring Context: 构建于Core封装包基础上的 Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明创建,比如说通过Servlet容器。

  3. Spring DAO: DAO (Data Access Object)提供了JDBC的抽象层,它可消除冗长的JDBC编码,保证数据库代码的简洁和解析数据库厂商特有的错误代码,它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层。 并且,它还利用 Spring 的 AOP 模块给 Spring 应用中的对象提供事务管理服务。而且对所有的POJOs(plain old Java objects)都适用。

  4. Spring ORM: ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,如前边提到的简单声明性事务管理。

  5. Spring AOP: Spring的 AOP 封装包提供了符合AOP Alliance规范的面向方面的编程实现,让你可以定义,例如方法拦截器(method-interceptors)和切点(pointcuts),从逻辑上讲,从而减弱代码的功能耦合,清晰的被分离开。而且,利用source-level的元数据功能,还可以将各种行为信息合并到你的代码中。

  6. Spring Web: Spring中的 Web 包提供了基础的针对Web开发的集成特性,例如多方文件上传,利用Servlet listeners进行IOC容器初始化和针对Web的ApplicationContext。当与WebWork或Struts一起使用Spring时,这个包使Spring可与其他框架结合。

  7. Spring Web MVC: Spring中的MVC封装包提供了Web应用的Model-View-Controller(MVC)实现。Spring的MVC框架并不是仅仅提供一种传统的实现,它提供了一种清晰的分离模型,在领域模型代码和Web Form之间。并且,还可以借助Spring框架的其他特性。

5. spring 中都用到了哪些设计模式?

  1. 工厂设计模式 : 比如通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象
  2. 代理设计模式 : AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理
  3. 单例设计模式 : Spring 中的 Bean 默认都是单例的
  4. 模板方法模式 : Spring 中 jdbcTemplate 等以 Template 结尾的对数据库操作的类,都会使用到模板方法设计模式,一些通用的功能
  5. 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源
  6. 观察者模式 : Spring 事件驱动模型观察者模式的
  7. 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式

6.什么是 Spring Boot?

Spring Boot 的核心设计思想是“约定优于配置”。基于这一设计原则,Spring Boot 极大地简化了项目和框架的配置。它采用了大量的默认配置来简化这些文件的配置过程,只需引入对应的 Starters(启动器)。

设计它就是为了使用最少的配置,以最快的速度来启动和运行 Spring 项目。

二. Spring IOC

这个讲的很好呀!
Spring IOC

1.什么是 Spring IOC 容器?

Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。

2.什么是依赖注入?

在依赖注入中,您不必创建对象,但必须描述如何创建它们。您不是直接在代码中将组件和服务连接在一起,而是描述配置文件中哪些组件需要哪些服务。由 IoC 容器将它们装配在一起。

3.可以通过多少种方式完成依赖注入?

  1. 构造器方法注入: 在bean标签内部使用 constructor-arg标签

    优点:创建时必须要指定构造方法中的全部参数,bean才能被创建,保证了对象创建出来之后,成员变量一定都有值

    缺点:必须要指定全部参数,否则无法创建,使用该方式改变了对象的创建过程

  2. Set属性注入:必须要有一个无参的构造方法,否则只能用构造方法构造

  3. 接口注入: 先定义一个接口,包含一个设置依赖的方法。然后依赖类,继承并实现这个接口。

4. 构造函数注入和 setter 注入区别

  1. 构造函数注入: 没有部分注入, 不会覆盖 setter 属性, 任意修改都会创建一个新实例, 适用于设置很多属性。
  2. setter 注入: 有部分注入, 会盖 setter 属性, 任意修改不会创建一个新实例, 适用于设置少量属性。

5. spring 中有多少种 IOC 容器?

spring 主要提供了两种 IOC 容器,一种是 BeanFactory,还有一种是 ApplicationContext。

  1. BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;
  2. ApplicationContext 面向使用Spring 框架的开发者, ApplicationContext 使用的“场合”较多。

功能上的区别:

  1. BeanFactory是Spring中最底层的接口,是IOC的核心,其功能包含了各种Bean的定义、加载、实例化、依赖注入和生命周期的管理。是IOC最基本的功能。
  2. ApplicationContext接口是BeanFactory的子类,具有BeanFactory所有的功能,同时继承了MessageSource,所以提供了更完整的框架功能,支持国际化、资源文件访问、载入多个上下文配置文件,使得每一个上下文都专注于一个特定层次,提供在监听器中注册bean事件。

加载方式的区别

  1. BeanFactory是延时加载,也就是说在容器启动时不会注入bean,而是在需要使用bean的时候,才会对该bean进行加载实例化。
  2. ApplicationContext 是在容器启动的时候,一次性创建所有的bean,所以运行的时候速度相对BeanFactory比较快。

因为加载方式的不同,导致BeanFactory无法提前发现spring存在的配置问题。(如果bean的某个属性没有注入,BeanFactory加载不会抛出异常,直至第一次调用getBean()方法时才会抛出异常。)但是ApplicationContext 在容器启动时就可以发现spring存在的配置问题,因为他是一次性加载的,有利于检测依赖属性是否注入(也因为其一次性加载的原因,导致占用内存空间,当Bean较多时,影响程序启动的速度)。

6. ApplicationContext 通常的实现是什么?

  1. FileSystemXmlApplicationContext :此容器从一个 XML 文件中加载 beans 的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
  2. ClassPathXmlApplicationContext:此容器也从一个 XML 文件中加载 beans 的定义, 你需要正确设置 classpath, 因为这个容器将在 classpath 里找 bean 配置。
  3. WebXmlApplicationContext:此容器加载一个 XML 文件,此文件定义了一个 WEB 应用的所有 bean。

7. IoC 的一些好处

  1. 它将最小化应用程序中的代码量。
  2. 它将使您的应用程序易于测试,因为它不需要单元测试用例中的任何单例或 JNDI 查找机制。
  3. 它以最小的影响和最少的侵入机制促进松耦合。
  4. 它支持即时的实例化和延迟加载服务。

8. Spring IoC 的实现机制

Spring 中的 IoC 的实现原理就是工厂模式加反射机制。

三. Spring Bean

1.什么是 Spring Bean?

  1. 它们是构成用户应用程序主干的对象。
  2. 它们由 SpringIoC 容器实例化,配置,装配和管理。
  3. Bean 是基于用户提供给容器的配置元数据创建。

2. spring 提供了哪些配置Bean的方式?

  1. 基于 xml 配置: bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。

  2. 基于注解配置: 通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身。默认情况下,Spring 容器中未打开注解装配。因此,需要在使用它之前在 Spring 配置文件中启用它, 例如 @Component, @Named, @Service, @Controller, @Repository。

  3. 基于类的Java Config: Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。
    (1) @Configuration 标注在类上,相当于把该类作为spring的xml配置文件中的
    (2) @Bean 注解扮演与 元素相同的角色, 它注释的方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
    (2) @Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。

3. Spring Bean 的作用域

Spring bean 支持 5 种 scope:

  1. Singleton: 每个 Spring IoC 容器仅有一个单实例(Spring 框架中的单例 bean 不是线程安全的)。
  2. Prototype: 线程每次调用这个 Bean 都会产生一个新的实例。
  3. Request: 每一次 HTTP 请求都会产生一个新的实例,并且该 bean 仅在当前 HTTP 请求内有效。
  4. Session: 每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。
  5. Global session: 类似于标准的 HTTP Session 作用域,不过它仅仅在基于 Portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 Portlet web 应用的各种不同的 Portlet 所共享。在 Global Session 作用域中定义的 Bean 被限定于全局 Portlet Session 的生命周期范围内。如果你在普通 Web 中使用 Global Session 作用域来标识 bean,那么 web会自动当成 session 类型来使用。

仅当用户使用支持 Web 的 ApplicationContext 时,最后三个才可用。

4.Spring Bean 容器的生命周期是什么样的?

  1. Spring 容器根据配置中的 bean 定义中实例化 bean。
  2. Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
  3. 如果 bean 实现BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用setBeanName()。
  4. 如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
  5. 如果存在与 bean 关联的任何BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
  6. 如果为 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。
  7. 最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用postProcessAfterInitialization() 方法。
  8. 如果 bean 实现DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
  9. 如果为bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。

简化版:

  1. 实例化: 实例化该 Bean 对象

  2. 填充属性,给该 Bean 赋值

  3. 初始化
    a. 如果实现了 Aware 接口,会通过其接口获取容器资源
    b. 如果实现了 BeanPostProcessor 接口,则会回调该接口的前置和后置处理增强
    c. 如果配置了 init-method 方法,会执行该方法

  4. 销毁
    a.如果实现了 DisposableBean 接口,则会回调该接口的 destroy 方法
    b.如果配置了 destroy-method 方法,则会执行 destroy-method 配置的方法

5.Spring中init-method和destroy-method的四种方式

在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等。

1. @Bean注解方式

public class Person {

    private String name;

    private Integer age;

    // 无参构造器
    public Person() {
        System.out.println("Person NoConstructor");
    }

    // 充当init method
    public void init() {
        System.out.println("Person init-method");
    }

    // 充当destroy method
    public void destroy() {
        System.out.println("Person destroy-method");
    }

}

创建好这个类,我们就可以使用@Bean注解的方式指定两个方法,以让他们生效。

@Configuration
@ComponentScan(value = "com.why.test.common.config")
public class AppConfig {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Person getPerson() {
        return new Person();
    }


    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        Person person = applicationContext.getBean(Person.class);
        System.out.println(person.getClass().getName());
        applicationContext.close();
    }

}

@Configuration注解是告诉spring这个类是一个配置类,相当于的xml文件

@ComponentScan则是指定需要spring来扫描的包,相当于xml中的context:component-scan属性

@Bean后边的 initMethod 和 destroyMethod 就是在声明这是一个 bean 的同时指定了 init 和 destroy 方法,方法名从功能实现上来说可以随意。

2. Xml配置方式

通过 bean 标签的 init-method 和 destroy-method 属性指定方法


<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">
 
	
	<bean id="person" class="com.why.test.common.config" init-method="init" destroy-method="destroy">
	bean>
beans>
	public static void main(String[] args) {
		// 用配置文件启动一个 ApplicationContext
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("context.xml");
		// 从context中取出我们的Bean,而不是用 new 对象的方式
		Person person = (Person) applicationContext.getBean("person");
		System.out.println(person.getClass().getName());
		applicationContext.close();
	}

3. @PostConstruct 和 @PreDestroy 注解

在init和destroy方法上加入了两个注解,@PostConstruct和上边@Bean后的initMethod相同,而@PreDestroy则是和destroyMethod做用相同。

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class Person {

    private String name;

    private Integer age;

    // 无参构造器
    public Person() {
        System.out.println("Person NoConstructor");
    }

    // 充当init method
    // 初始化方法的注解方式 等同于init-method
    @PostConstruct
    public void init() {
        System.out.println("Person init-method");
    }

    // 充当destroy method
    // 销毁方法的注解方式 等同于destroy-method
    @PreDestroy
    public void destroy() {
        System.out.println("Person destroy-method");
    }

}
@Configuration
@ComponentScan(value = "com.why.test.common.config")
public class AppConfig {

    @Bean
    public Person getPerson() {
        return new Person();
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        Person person = applicationContext.getBean(Person.class);
        System.out.println(person.getClass().getName());
        applicationContext.close();
    }
}

4. 继承 InitializingBean 和 DisposableBean

public class Person implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Person init-method");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Person destroy-method");
    }

}

测试形式与3相同

5.什么是 spring 装配

当 bean 在 Spring 容器中组合在一起时, 它被称为装配或 bean 装配。
Spring容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean。

6.什么是 spring 自动装配

自动装配就是指 Spring 容器在不使用 和 标签的情况下,可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。

7.自动装配和自动注入的区别

7.1 自动装配(Autowiring):

自动装配是一种机制,用于告诉依赖注入容器如何为一个组件(通常是一个Bean或类)自动解析和注入其依赖。自动装配可以减少手动配置和编码的工作量,使得系统更容易维护和扩展。

Spring框架是一个典型的使用自动装配的例子。在Spring中,您可以使用注解或XML配置来启用自动装配。Spring支持不同的自动装配模式,包括:

  • 按类型自动装配:容器会尝试将一个Bean的依赖与容器中的其他Bean匹配,通过数据类型来确定匹配。这是最常见的自动装配方式。
  • 按名称自动装配:容器会尝试将一个Bean的依赖与容器中的其他Bean匹配,通过Bean的名称来确定匹配。
  • 构造器自动装配:容器会查找与构造器参数数据类型匹配的Bean,并将它们注入到构造器中。
  • 属性自动装配:容器会查找与Bean属性数据类型匹配的Bean,并将它们注入到属性中。

7.2 自动注入(Dependency Injection):

自动注入是依赖注入(Dependency Injection)的一种实现方式。它是一种设计模式,通过它,一个类的依赖关系(通常是其他类或对象)被注入到该类中,而不是由该类自己创建或查找依赖。这样可以实现松耦合,提高了代码的可测试性、可维护性和可扩展性。

自动注入的方式包括:

a. 构造器注入:依赖通过类的构造器注入。这是一种常见的自动注入方式,通常用于注入不变的依赖关系。
b. 属性注入:依赖通过类的属性(通常是setter方法)注入。这是另一种常见的自动注入方式,通常用于可变的依赖关系。
c. 方法注入:依赖通过类的方法注入。这是一种相对较少使用的方式,通常在特殊情况下使用。

8. 自动装配有哪些方式?

Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。
使通过xml文件 元素的autowire属性或者注解(需要在xml 中写入context:annotation-config/ 开启注解功能) 进行自动装配。

autowire 属性有五个值:

  1. no: 这是默认设置,表示没有自动装配。应使用显式 bean 引用进行装配。
  2. byName: 它根据 bean 的名称注入对象依赖项。它匹配并装配其属性与 XML文件中由相同名称定义的 bean。
  3. byType: 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。
  4. 构造函数: 它通过调用类的构造函数来注入依赖项。它有大量的参数。
  5. autodetect: 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配。

9.开启自动装配的注解有哪些?

  1. @Autowired:可以应用到 Bean 的属性变量、属性的 setter 方法、非 setter 方法及构造函数等,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功,如果ioc容器中没有任何bean类型和要注入的变量类型匹配则报错。如果想按照名称来装配注入,则需要结合 @Qualifier 一起使用;

  2. @Qualifier:与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。它在给类成员注入时不能单独使用必须要和@Autowired,但是在给方法参数注入时可以单独使用。

  3. @Resource:作用于@Autowired相同,区别在于@Resource可以通过Bean实例名称进行装配,也就是@Resource中的两个重要属性name和type, 与@Autowired不一样的是,它默认是按照组件名称进行装配的,按照组件名称找不到在根据属性类型去查找,再找不到就报错;他们另一个不同的地方就是 @Autowired 是Spring定义的, @Resource是jdk提供的。

10.自动装配有什么局限

  1. 覆盖的可能性: 始终可以使用 和 设置指定依赖项,这将覆盖自动装配。
  2. 基本数据类型: 简单属性(如基本数据类型 int、boolean,字符串)无法自动装配。
  3. 模糊特性:自动装配不如显式装配精确,建议使用显式装配

11.@Component, @Controller, @Repository, @Service 有何区别

  1. @Component :这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。

  2. @Controller :这将一个类标记为 Spring Web MVC 控制器。标有它的Bean 会自动导入到 IoC 容器中。

  3. @Service :此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用@Service 而不是 @Component,因为它以更好的方式指定了意图。

  4. @Repository :这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。

12.@Required 注解有什么用?

@Required 注解主要用在 setter 方法上,它表示该 setter 方法的属性必须要在配置时注入值。否则就会报 BeanInitializationException 异常。

13.@RequestMapping 注解有什么用?

@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。

此注释可应用于两个级别:

  1. 类级别:映射请求的 URL。
  2. 方法级别:映射 URL 以及 HTTP 请求方法。

14.什么是 Spring 的内部 bean?

只有将 bean 用作另一个 bean 的属性时,才能将 bean 声明为内部 bean。为了定义 bean,Spring 的基于 XML 的配置元数据在 或 中提供了 元素的使用。
内部 bean 总是匿名的。

public class Student {
    private Person person;
}

public class Person {
    private String name;
    private String address;
}

    <property name="person">
        
        <bean class="com.why.test.common.config.Person">
            property>
            <property name="address" value="北京">property>
        bean>
    property>
bean>

五.Spring AOP

1. 什么是 AOP?

AOP(Aspect-Oriented Programming), 即面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。

AOP 是 OOP(面向对象编程) 的延续,是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2.AOP 有哪些实现方式?

实现 AOP 的技术,主要分为两大类:

  1. 静态代理
    AOP 框架在 编译阶段 对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
    a. 编译时编织(特殊编译器实现)
    b. 类加载时编织(特殊的类加载器实现)。

  2. 动态代理
    AOP 框架在 运行阶段 对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。
    a. JDK 动态代理
    b. CGLIB

spring 中 AOP 的实现是「通过动态代理实现的」,如果是实现了接口就会使用 JDK 动态代理,否则就使用 CGLIB 代理。

3.动态代理和静态代理有什么区别?

  1. 静态代理
    a.由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在
    b.静态代理通常只代理一个类
    c.静态代理事先知道要代理的是什么

  2. 动态代理
    a.在程序运行时,运用反射机制动态创建而成
    b.动态代理是代理一个接口下的多个实现类
    c.动态代理不知道要代理什么东西,只有在运行时才知道

4.JDK 动态代理和 CGLIB 代理有什么区别?

  1. JDK 动态代理时被代理的对象必须要实现某个接口,然后基于反射机制,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。
  2. 没有实现接口的对象,无法使用 JDK Proxy 进行代理, 这时候使用 CGLIB动态代理, CGLIB 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,然后重写父类的方法,实现对代码的增强。

5.Spring AOP and AspectJ AOP 有什么区别?

  1. Spring AOP 在运行时增强,通过动态代理实现,如 Java JDK的动态代理(Proxy,底层通过反射实现)或者CGLIB的动态代理(底层通过继承实现)。作用于运行期,字节码加载后,使用了反射,所以性能较差。

  2. AspectJ 是编译时增强,原理是静态代理, 通过修改代码来实现的。

  • 编译时织入(CTW):在编译时织入中,AspectJ编译器(ajc)会在编译源代码时,根据AspectJ的语法和指令,将切面的逻辑织入到目标代码中。这种织入方式要求使用AspectJ编译器进行编译,并且在编译时指定切面的织入规则和目标代码。

  • 编译后织入(PCW):编译后织入是指在目标代码编译完成后,通过特定的工具或框架将切面逻辑织入到目标类中。这种织入方式可以在不修改原始源代码的情况下,对已编译的目标类进行增强。常用的工具包括AspectJ提供的ajc命令行工具和Maven或Gradle等构建工具的插件。

  • 类加载时织入(LTW):类加载时织入是指在类加载过程中,通过特定的类加载器和字节码增强技术,在目标类被加载到JVM时将切面逻辑织入其中。这种织入方式相对于编译时织入和编译后织入更为灵活,可以在运行时动态地将切面逻辑织入目标类。AspectJ提供了基于Java Agent的LTW实现,可以通过Java Agent机制来实现类加载时织入。

Spring AOP AspectJ
Java 中实现 使用 Java 编程语言的扩展实现
不需要单独的编译过程 除非设置 LTW,否则需要 AspectJ 编译器(ajc)
只能使用运行时织入 运行时织入不可用。支持编译时、编译后和类加载时织入
仅支持方法级编织 可以编织字段、方法、构造函数、静态初始值设定项、最终类/方法等
只能在由 Spring 容器管理的 bean 上实现 可以在所有域对象上实现
仅支持方法执行切入点 支持所有切入点
代理是由目标对象创建的,并且切面应用在这些代理上 在执行应用程序之前(运行时) 直接在代码中进行织入
比 AspectJ 慢多 更好的性能
易于学习和应用 相对于Spring AOP来说更复杂

6.什么是 Aspect?

aspect 由 pointcount 和 advice 组成, 它既包含了横切逻辑的定义, 也包括了连接点的定义. Spring AOP 就是负责实施切面的框架, 它将切面所定义的横切逻辑编织到切面所指定的连接点中。

AOP 的工作重心在于如何将增强编织目标对象的连接点上, 这里包含两个工作:

  1. 如何通过 pointcut 和 advice 定位到特定的 joinpoint 上
  2. 如何在 advice 中编写切面代码
  3. 可以简单地认为, 使用 @Aspect 注解的类就是切面

7.什么是切点(JoinPoint)

程序运行中的一些时间点, 例如一个方法的执行, 或者是一个异常的处理。在 Spring AOP 中, join point 总是方法的执行点。

8.什么是通知(Advice)

特定 JoinPoint 处的 Aspect 所采取的动作称为 Advice。Spring AOP 使用一个 Advice 作为拦截器,在 JoinPoint “周围”维护一系列的拦截器。

9.有哪些类型的通知(Advice)?

  1. Before: 这些类型的 Advice 在 joinpoint 方法之前执行,并使用@Before 注解标记进行配置。
  2. After Returning: 这些类型的 Advice 在连接点方法正常执行后执行,并使用@AfterReturning 注解标记进行配置。
  3. After Throwing: 这些类型的 Advice 仅在 joinpoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。
  4. After (finally): 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。
  5. Around: 这些类型的 Advice 在连接点之前和之后执行,并使用@Around 注解标记进行配置。

10.Spring aop 中 concern 和 cross-cutting concern 的不同之处

  1. concern 是我们想要在应用程序的特定模块中定义的行为。它可以定义为我们想要实现的功能。
  2. cross-cutting concern 是一个适用于整个应用的行为,这会影响整个应用程序。例如,日志记录,安全性和数据传输是应用程序几乎每个模块都需要关注的问题,因此它们是跨领域的问题。

六.Spring MVC

1.Spring MVC 框架有什么用?

Spring 配备构建 Web 应用的全功能 MVC 框架。Spring 可以很便捷地和其他 MVC 框架集成,如 Struts,Spring 的 MVC 框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。

Spring Web MVC 框架提供 模型-视图-控制器 架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序。
MVC 模式有助于分离应用程序的不同方面,如输入逻辑,业务逻辑和 UI 逻辑,同时在所有这些元素之间提供松散耦合。

2.描述一下 DispatcherServlet 的工作流程

Spring 的 MVC 框架是围绕 DispatcherServlet 来设计的,它用来处理所有的 HTTP 请求和响应。

Spring总结_第1张图片

  1. 向服务器发送 HTTP 请求,请求被前端控制器 DispatcherServlet 捕获。

  2. DispatcherServlet 根据 -servlet.xml 中的配置对请求的 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回。

  3. DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。(附注:如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(…)方法)。

  4. 提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler( Controller)。在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
    4.1 HttpMessageConveter:将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息。
    4.2 数据转换:对请求消息进行数据转换。如 String转换成 Integer、Double等。
    4.3 数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等。
    4.4 数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或 Error中。

  5. Handler(Control ler)执行完成后,向 DispatcherServlet 返回一个ModelAndView 对象;

  6. 根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver)返回给 DispatcherServlet。

  7. ViewResolver 结合 Model 和 View,来渲染视图。

  8. 视图负责将渲染结果返回给客户端。

你可能感兴趣的:(spring,java,后端)