[Spring]Spring
说一下你对 Spring 的理解
Spring框架核心特性包括:
- IoC容器:Spring通过控制反转实现了对象的创建和对象间的依赖关系管理。开发者只需要定义好Bean及其依赖关系,Spring容器负责创建和组装这些对象。
- AOP:面向切面编程,允许开发者定义横切关注点,例如事务管理、安全控制等,独立于业务逻辑的代码。通过AOP,可以将这些关注点模块化,提高代码的可维护性和可重用性。
- 事务管理:Spring提供了一致的事务管理接口,支持声明式和编程式事务。开发者可以轻松地进行事务管理,而无需关心具体的事务API。
- MVC框架:Spring MVC是一个基于Servlet API构建的Web框架,采用了模型-视图-控制器(MVC)架构。它支持灵活的URL到页面控制器的映射,以及多种视图技术。
Spring IoC和AOP 介绍一下
Spring IoC和AOP 区别:
-
IoC:即控制反转的意思,它是一种创建和获取对象的技术思想,依赖注入(DI)是实现这种技术的一种方式。传统开发过程中,我们需要通过new关键字来创建对象。使用IoC思想开发方式的话,我们不通过new关键字创建对象,而是通过IoC容器来帮我们实例化对象。 通过IoC的方式,可以大大降低对象之间的耦合度。
-
AOP:是面向切面编程,能够将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,以减少系统的重复代码,降低模块间的耦合度。Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理。
在 Spring 框架中,IOC 和 AOP 结合使用,可以更好地实现代码的模块化和分层管理。例如:
通过 IOC 容器管理对象的依赖关系,然后通过 AOP 将横切关注点统一切入到需要的业务逻辑中。
使用 IOC 容器管理 Service 层和 DAO 层的依赖关系,然后通过 AOP 在 Service 层实现事务管理、日志记录等横切功能,使得业务逻辑更加清晰和可维护。
Spring的aop介绍一下
Spring AOP是Spring框架中的一个重要模块,用于实现面向切面编程。
我们知道,Java 就是一门面向对象编程的语言,在 OOP 中最小的单元就是“Class 对象”,但是在 AOP 中最小的单元是“切面”。一个“切面”可以包含很多种类型和对象,对它们进行模块化管理,例如事务管理。
在面向切面编程的思想里面,把功能分为两种
核心业务:登陆、注册、增、删、改、查、都叫核心业务
周边功能:日志、事务管理这些次要的为周边业务
在面向切面编程中,核心业务功能和周边功能是分别独立进行开发,两者不是耦合的,然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP。
AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
在 AOP 中有以下几个概念:
- AspectJ:切面,只是一个概念,没有具体的接口或类与之对应,是 Join point,Advice 和 Pointcut 的一个统称。
- Join point:连接点,指程序执行过程中的一个点,例如方法调用、异常处理等。在 Spring AOP 中,仅支持方法级别的连接点。
- Advice:通知,即我们定义的一个切面中的横切逻辑,有“around”,“before”和“after”三种类型。在很多的 AOP 实现框架中,Advice 通常作为一个拦截器,也可以包含许多个拦截器作为一条链路围绕着 Join point 进行处理。
- Pointcut:切点,用于匹配连接点,一个 AspectJ 中包含哪些 Join point 需要由 Pointcut 进行筛选。
- Introduction:引介,让一个切面可以声明被通知的对象实现任何他们没有真正实现的额外的接口。例如可以让一个代理对象代理两个目标类。
- Weaving:织入,在有了连接点、切点、通知以及切面,如何将它们应用到程序中呢?没错,就是织入,在切点的引导下,将通知逻辑插入到目标方法上,使得我们的通知逻辑在方法调用时得以执行。
- AOP proxy:AOP 代理,指在 AOP 实现框架中实现切面协议的对象。在 Spring AOP 中有两种代理,分别是 JDK 动态代理和 CGLIB 动态代理。
- Target object:目标对象,就是被代理的对象。
Spring AOP 是基于 JDK 动态代理和 Cglib 提升实现的,两种代理方式都属于运行时的一个方式,所以它没有编译时的一个处理,那么因此 Spring 是通过 Java 代码实现的。
IOC和AOP是通过什么机制来实现的?
Spring IOC 实现机制
反射:Spring IOC容器利用Java的反射机制动态地加载类、创建对象实例及调用对象方法,反射允许在运行时检查类、方法、属性等信息,从而实现灵活的对象实例化和管理。
依赖注入:IOC的核心概念是依赖注入,即容器负责管理应用程序组件之间的依赖关系。Spring通过构造函数注入、属性注入或方法注入,将组件之间的依赖关系描述在配置文件中或使用注解。
设计模式 - 工厂模式:Spring IOC容器通常采用工厂模式来管理对象的创建和生命周期。容器作为工厂负责实例化Bean并管理它们的生命周期,将Bean的实例化过程交给容器来管理。
容器实现:Spring IOC容器是实现IOC的核心,通常使用BeanFactory或ApplicationContext来管理Bean。BeanFactory是IOC容器的基本形式,提供基本的IOC功能;ApplicationContext是BeanFactory的扩展,并提供更多企业级功能。
Spring AOP 实现机制
Spring AOP的实现依赖于动态代理技术。动态代理是在运行时动态生成代理对象,而不是在编译时。它允许开发者在运行时指定要代理的接口和行为,从而实现在不修改源码的情况下增强方法的功能。
Spring AOP支持两种动态代理:
基于JDK的动态代理:使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。这种方式需要代理的类实现一个或多个接口。
基于CGLIB的动态代理:当被代理的类没有实现接口时,Spring会使用CGLIB库生成一个被代理类的子类作为代理。CGLIB(Code Generation Library)是一个第三方代码生成库,通过继承方式实现代理。
怎么理解SpringIoc?
IOC:Inversion Of Control,即控制反转,是一种设计思想。在传统的 Java SE 程序设计中,我们直接在对象内部通过 new 的方式来创建对象,是程序主动创建依赖对象;
img
而在Spring程序设计中,IOC 是有专门的容器去控制对象。
img
所谓控制就是对象的创建、初始化、销毁。
创建对象:原来是 new 一个,现在是由 Spring 容器创建。
初始化对象:原来是对象自己通过构造器或者 setter 方法给依赖的对象赋值,现在是由 Spring 容器自动注入。
销毁对象:原来是直接给对象赋值 null 或做一些销毁操作,现在是 Spring 容器管理生命周期负责销毁对象。
总结:IOC 解决了繁琐的对象生命周期的操作,解耦了我们的代码。所谓反转:其实是反转的控制权,前面提到是由 Spring 来控制对象的生命周期,那么对象的控制就完全脱离了我们的控制,控制权交给了 Spring 。这个反转是指:我们由对象的控制者变成了 IOC 的被动控制者。
依赖倒置,依赖注入,控制反转分别是什么?
控制反转:“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。
依赖注入:依赖注入和控制反转恰恰相反,它是一种具体的编码技巧。我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。
依赖倒置:这条原则跟控制反转有点类似,主要用来指导框架层面的设计。高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象。
如果让你设计一个SpringIoc,你觉得会从哪些方面考虑这个设计?
Bean的生命周期管理:需要设计Bean的创建、初始化、销毁等生命周期管理机制,可以考虑使用工厂模式和单例模式来实现。
依赖注入:需要实现依赖注入的功能,包括属性注入、构造函数注入、方法注入等,可以考虑使用反射机制和XML配置文件来实现。
Bean的作用域:需要支持多种Bean作用域,比如单例、原型、会话、请求等,可以考虑使用Map来存储不同作用域的Bean实例。
AOP功能的支持:需要支持AOP功能,可以考虑使用动态代理机制和切面编程来实现。
异常处理:需要考虑异常处理机制,包括Bean创建异常、依赖注入异常等,可以考虑使用try-catch机制来处理异常。
配置文件加载:需要支持从不同的配置文件中加载Bean的相关信息,可以考虑使用XML、注解或者Java配置类来实现。
SpringAOP主要想解决什么问题
它的目的是对于面向对象思维的一种补充,而不是像引入命令式、函数式编程思维让他顺应另一种开发场景。在我个人的理解下AOP更像是一种对于不支持多继承的弥补,除开对象的主要特征(我更喜欢叫“强共性”)被抽象为了一条继承链路,对于一些“弱共性”,AOP可以统一对他们进行抽象和集中处理。
举一个简单的例子,打印日志。需要打印日志可能是许多对象的一个共性,这在企业级开发中十分常见,但是日志的打印并不反应这个对象的主要共性。而日志的打印又是一个具体的内容,它并不抽象,所以它的工作也不可以用接口来完成。而如果利用继承,打印日志的工作又横跨继承树下面的多个同级子节点,强行侵入到继承树内进行归纳会干扰这些强共性的区分。
这时候,我们就需要AOP了。AOP首先在一个Aspect(切面)里定义了一些Advice(增强),其中包含具体实现的代码,同时整理了切入点,切入点的粒度是方法。最后,我们将这些Advice织入到对象的方法上,形成了最后执行方法时面对的完整方法。
img
SpringAOP的原理了解吗
Spring AOP的实现依赖于动态代理技术。动态代理是在运行时动态生成代理对象,而不是在编译时。它允许开发者在运行时指定要代理的接口和行为,从而实现在不修改源码的情况下增强方法的功能。
Spring AOP支持两种动态代理:
基于JDK的动态代理:使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。这种方式需要代理的类实现一个或多个接口。
基于CGLIB的动态代理:当被代理的类没有实现接口时,Spring会使用CGLIB库生成一个被代理类的子类作为代理。CGLIB(Code Generation Library)是一个第三方代码生成库,通过继承方式实现代理。
动态代理是什么?
Java的动态代理是一种在运行时动态创建代理对象的机制,主要用于在不修改原始类的情况下对方法调用进行拦截和增强。
Java动态代理主要分为两种类型:
基于接口的代理(JDK动态代理): 这种类型的代理要求目标对象必须实现至少一个接口。Java动态代理会创建一个实现了相同接口的代理类,然后在运行时动态生成该类的实例。这种代理的实现核心是java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。每一个动态代理类都必须实现InvocationHandler接口,并且每个代理类的实例都关联到一个handler。当通过代理对象调用一个方法时,这个方法的调用会被转发为由InvocationHandler接口的invoke()方法来进行调用。
基于类的代理(CGLIB动态代理): CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它可以在运行时动态生成一个目标类的子类。CGLIB代理不需要目标类实现接口,而是通过继承的方式创建代理类。因此,如果目标对象没有实现任何接口,可以使用CGLIB来创建动态代理。
动态代理和静态代理的区别
代理是一种常用的设计模式,目的是:为其他对象提供一个代理以控制对某个对象的访问,将两个类的关系解耦。代理类和委托类都要实现相同的接口,因为代理真正调用的是委托类的方法。
区别:
静态代理:由程序员创建或者是由特定工具创建,在代码编译时就确定了被代理的类是一个静态代理。静态代理通常只代理一个类;
动态代理:在代码运行期间,运用反射机制动态创建生成。动态代理代理的是一个接口下的多个实现类。
AOP实现有哪些注解?
常用的注解包括:
@Aspect:用于定义切面,标注在切面类上。
@Pointcut:定义切点,标注在方法上,用于指定连接点。
@Before:在方法执行之前执行通知。
@After:在方法执行之后执行通知。
@Around:在方法执行前后都执行通知。
@AfterReturning:在方法执行后返回结果后执行通知。
@AfterThrowing:在方法抛出异常后执行通知。
@Advice:通用的通知类型,可以替代@Before、@After等。
什么是反射?有哪些使用场景?
反射具有以下特性:
运行时类信息访问:反射机制允许程序在运行时获取类的完整结构信息,包括类名、包名、父类、实现的接口、构造函数、方法和字段等。
动态对象创建:可以使用反射API动态地创建对象实例,即使在编译时不知道具体的类名。这是通过Class类的newInstance()方法或Constructor对象的newInstance()方法实现的。
动态方法调用:可以在运行时动态地调用对象的方法,包括私有方法。这通过Method类的invoke()方法实现,允许你传入对象实例和参数值来执行方法。
访问和修改字段值:反射还允许程序在运行时访问和修改对象的字段值,即使是私有的。这是通过Field类的get()和set()方法完成的。
img
Java反射机制在spring框架中,很多地方都用到了反射,让我们来看看Spring的IoC和AOP是如何使用反射技术的。
1、Spring框架的依赖注入(DI)和控制反转(IoC)
Spring 使用反射来实现其核心特性:依赖注入。
在Spring中,开发者可以通过XML配置文件或者基于注解的方式声明组件之间的依赖关系。当应用程序启动时,Spring容器会扫描这些配置或注解,然后利用反射来实例化Bean(即Java对象),并根据配置自动装配它们的依赖。
例如,当一个Service类需要依赖另一个DAO类时,开发者可以在Service类中使用@Autowired注解,而无需自己编写创建DAO实例的代码。Spring容器会在运行时解析这个注解,通过反射找到对应的DAO类,实例化它,并将其注入到Service类中。这样不仅降低了组件之间的耦合度,也极大地增强了代码的可维护性和可测试性。
2、动态代理的实现
在需要对现有类的方法调用进行拦截、记录日志、权限控制或是事务管理等场景中,反射结合动态代理技术被广泛应用。
一个典型的例子是Spring AOP(面向切面编程)的实现。Spring AOP允许开发者定义切面(Aspect),这些切面可以横切关注点(如日志记录、事务管理),并将其插入到业务逻辑中,而不需要修改业务逻辑代码。
例如,为了给所有的服务层方法添加日志记录功能,可以定义一个切面,在这个切面中,Spring会使用JDK动态代理或CGLIB(如果目标类没有实现接口)来创建目标类的代理对象。这个代理对象在调用任何方法前或后,都会执行切面中定义的代码逻辑(如记录日志),而这一切都是在运行时通过反射来动态构建和执行的,无需硬编码到每个方法调用中。
这两个例子展示了反射机制如何在实际工程中促进松耦合、高内聚的设计,以及如何提供动态、灵活的编程能力,特别是在框架层面和解决跨切面问题时。
spring框架中都用到了哪些设计模式
- 工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
- 代理设计模式 : Spring AOP 功能的实现。
- 单例设计模式 : Spring 中的 Bean 默认都是单例的。
- 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
- 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
- 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
spring 常用注解有什么?
@Autowired 注解#
@Autowired:主要用于自动装配bean。当Spring容器 (opens new window)中存在与要注入的属性类型匹配的bean时,它会自动将bean注入到属性中。就跟我们new 对象一样。
用法很简单,如下示例代码:
@Component
public class MyService {
}
@Component
public class MyController {
@Autowired
private MyService myService;
}
在上面的示例代码中,MyController类中的myService属性被@Autowired注解标记,Spring会自动将MyService类型的bean注入到myService属性中。
@Component#
这个注解用于标记一个类作为Spring的bean。当一个类被@Component注解标记时,Spring会将其实例化为一个bean,并将其添加到Spring容器中。在上面讲解@Autowired的时候也看到了,示例代码:
@Component
public class MyComponent {
}
在上面的示例代码中,MyComponent类被@Component注解标记,Spring会将其实例化为一个bean,并将其添加到Spring容器中。
@Configuration#
@Configuration,注解用于标记一个类作为Spring的配置类。配置类可以包含@Bean注解的方法,用于定义和配置bean,作为全局配置。示例代码:
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@Bean#
@Bean注解用于标记一个方法作为Spring的bean工厂方法。当一个方法被@Bean注解标记时,Spring会将该方法的返回值作为一个bean,并将其添加到Spring容器中,如果自定义配置,经常用到这个注解。
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@Service#
@Service,这个注解用于标记一个类作为服务层的组件。它是@Component注解的特例,用于标记服务层的bean,一般标记在业务service的实现类。
@Service
public class MyServiceImpl {
}
@Repository#
@Repository注解用于标记一个类作为数据访问层的组件。它也是@Component注解的特例,用于标记数据访问层的bean。这个注解很容易被忽略,导致数据库无法访问。
@Repository
public class MyRepository {
}
在上面的示例代码中,MyRepository类被@Repository注解标记,Spring会将其实例化为一个bean,并将其添加到Spring容器中。
@Controller#
@Controller注解用于标记一个类作为控制层的组件。它也是@Component注解的特例,用于标记控制层的bean。这是MVC结构的另一个部分,加在控制层
@Controller
public class MyController {
}
在上面的示例代码中,MyController类被@Controller注解标记,Spring会将其实例化为一个bean,并将其添加到Spring容器中。
Spring的事务什么情况下会失效?
Spring Boot通过Spring框架的事务管理模块来支持事务操作。事务管理在Spring Boot中通常是通过 @Transactional 注解来实现的。事务可能会失效的一些常见情况包括:
未捕获异常: 如果一个事务方法中发生了未捕获的异常,并且异常未被处理或传播到事务边界之外,那么事务会失效,所有的数据库操作会回滚。
非受检异常: 默认情况下,Spring对非受检异常(RuntimeException或其子类)进行回滚处理,这意味着当事务方法中抛出这些异常时,事务会回滚。
事务传播属性设置不当: 如果在多个事务之间存在事务嵌套,且事务传播属性配置不正确,可能导致事务失效。特别是在方法内部调用有 @Transactional 注解的方法时要特别注意。
多数据源的事务管理: 如果在使用多数据源时,事务管理没有正确配置或者存在多个 @Transactional 注解时,可能会导致事务失效。
跨方法调用事务问题: 如果一个事务方法内部调用另一个方法,而这个被调用的方法没有 @Transactional 注解,这种情况下外层事务可能会失效。
事务在非公开方法中失效: 如果 @Transactional 注解标注在私有方法上或者非 public 方法上,事务也会失效。
Spring的事务,使用this调用是否生效?
不能生效。
因为Spring事务是通过代理对象来控制的,只有通过代理对象的方法调用才会应用事务管理的相关规则。当使用this直接调用时,是绕过了Spring的代理机制,因此不会应用事务设置。
Bean的生命周期说一下?
- Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化。
- Bean实例化后对将Bean的引入和值注入到Bean的属性中
- 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
- 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
- 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
- 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
- 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
- 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
- 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
在Spring中,在bean加载/销毁前后,如果想实现某些逻辑,可以怎么做
在Spring框架中,如果你希望在Bean加载(即实例化、属性赋值、初始化等过程完成后)或销毁前后执行某些逻辑,你可以使用Spring的生命周期回调接口或注解。这些接口和注解允许你定义在Bean生命周期的关键点执行的代码。
使用init-method和destroy-method
在XML配置中,你可以通过init-method和destroy-method属性来指定Bean初始化后和销毁前需要调用的方法。
然后,在你的Bean类中实现这些方法:
public class MyBeanClass {
public void init() {
// 初始化逻辑
}
public void destroy() {
// 销毁逻辑
}
}
实现InitializingBean和DisposableBean接口
你的Bean类可以实现org.springframework.beans.factory.InitializingBean和org.springframework.beans.factory.DisposableBean接口,并分别实现afterPropertiesSet和destroy方法。
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class MyBeanClass implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
}
@Override
public void destroy() throws Exception {
// 销毁逻辑
}
}
使用@PostConstruct和@PreDestroy注解
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class MyBeanClass {
@PostConstruct
public void init() {
// 初始化逻辑
}
@PreDestroy
public void destroy() {
// 销毁逻辑
}
}
使用@Bean注解的initMethod和destroyMethod属性
在基于Java的配置中,你还可以在@Bean注解中指定initMethod和destroyMethod属性。
@Configuration
public class AppConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public MyBeanClass myBean() {
return new MyBeanClass();
}
}
Spring给我们提供了很多扩展点,这些有了解吗?
Spring框架提供了许多扩展点,使得开发者可以根据需求定制和扩展Spring的功能。以下是一些常用的扩展点:
- BeanFactoryPostProcessor:允许在Spring容器实例化bean之前修改bean的定义。常用于修改bean属性或改变bean的作用域。
- BeanPostProcessor:可以在bean实例化、配置以及初始化之后对其进行额外处理。常用于代理bean、修改bean属性等。
- PropertySource:用于定义不同的属性源,如文件、数据库等,以便在Spring应用中使用。
- ImportSelector和ImportBeanDefinitionRegistrar:用于根据条件动态注册bean定义,实现配置类的模块化。
- Spring MVC中的HandlerInterceptor:用于拦截处理请求,可以在请求处理前、处理中和处理后执行特定逻辑。
- Spring MVC中的ControllerAdvice:用于全局处理控制器的异常、数据绑定和数据校验。
- Spring Boot的自动配置:通过创建自定义的自动配置类,可以实现对框架和第三方库的自动配置。
- 自定义注解:创建自定义注解,用于实现特定功能或约定,如权限控制、日志记录等。
MVC分层介绍一下
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
视图(view): 为用户提供使用界面,与用户直接进行交互。
模型(model): 代表一个存取数据的对象或 JAVA POJO(Plain Old Java Object,简单java对象)。它也可以带有逻辑,主要用于承载数据,并对用户提交请求进行计算的模块。模型分为两类,一类称为数据承载 Bean,一类称为业务处理Bean。所谓数据承载 Bean 是指实体类(如:User类),专门为用户承载业务数据的;而业务处理 Bean 则是指Service 或 Dao 对象, 专门用于处理用户提交请求的。
控制器(controller): 用于将用户请求转发给相应的 Model 进行处理,并根据 Model 的计算结果向用户提供相应响应。它使视图与模型分离。
img
流程步骤:
用户通过View 页面向服务端提出请求,可以是表单请求、超链接请求、AJAX 请求等;
服务端 Controller 控制器接收到请求后对请求进行解析,找到相应的Model,对用户请求进行处理Model 处理;
将处理结果再交给 Controller(控制器其实只是起到了承上启下的作用);
根据处理结果找到要作为向客户端发回的响应View 页面,页面经渲染后发送给客户端。
了解SpringMVC的处理流程吗?
Spring MVC的工作流程如下:
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用处理器映射器HandlerMapping。
- 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
- DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
- 执行处理器Handler(Controller,也叫页面控制器)。
- Handler执行完成返回ModelAndView
- HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
- DispatcherServlet响应用户。
Handlermapping 和 handleradapter有了解吗?
HandlerMapping:
- 作用:HandlerMapping负责将请求映射到处理器(Controller)。
- 功能:根据请求的URL、请求参数等信息,找到处理请求的 Controller。
- 类型:Spring提供了多种HandlerMapping实现,如BeanNameUrlHandlerMapping、RequestMappingHandlerMapping等。
- 工作流程:根据请求信息确定要请求的处理器(Controller)。HandlerMapping可以根据URL、请求参数等规则确定对应的处理器。
HandlerAdapter:
- 作用:HandlerAdapter负责调用处理器(Controller)来处理请求。
- 功能:处理器(Controller)可能有不同的接口类型(Controller接口、HttpRequestHandler接口等),HandlerAdapter根据处理器的类型来选择合适的方法来调用处理器。
- 类型:Spring提供了多个HandlerAdapter实现,用于适配不同类型的处理器。
- 工作流程:根据处理器的接口类型,选择相应的HandlerAdapter来调用处理器。
工作流程:
当客户端发送请求时,HandlerMapping根据请求信息找到对应的处理器(Controller)。
HandlerAdapter根据处理器的类型选择合适的方法来调用处理器。
处理器执行相应的业务逻辑,生成ModelAndView。
HandlerAdapter将处理器的执行结果包装成ModelAndView。
视图解析器根据ModelAndView找到对应的视图进行渲染。
将渲染后的视图返回给客户端。
HandlerMapping和HandlerAdapter协同工作,通过将请求映射到处理器,并调用处理器来处理请求,实现了请求处理的流程。它们的灵活性使得在Spring MVC中可以支持多种处理器和处理方式,提高了框架的扩展性和适应性。
Spring 和 SpringBoot 的区别#
- 配置方式不同
传统的Spring框架依赖于XML或注解方式进行配置。开发者经常需要花费大量时间去调整和管理XML配置。而Spring Boot鼓励基于Java的配置,减少了对XML配置的依赖。
-
项目启动方式不同
在传统的Spring项目中,开发者需要部署应用到外部的应用服务器上。而Spring Boot提供了一个main方法,允许应用作为一个独立的Java应用来运行,简化了部署和测试过程。 -
依赖管理不同
Spring Boot通过提供“starters”简化了依赖管理。开发者只需添加一个“starter”依赖,Spring Boot会自动为你解决版本问题和其他依赖。
-
自动化配置
Spring Boot具有自动配置功能,它会根据项目中的依赖自动配置Spring。例如,如果你的项目中有spring-boot-starter-web,Spring Boot会自动配置一个嵌入式的Tomcat服务器。 -
内置服务器
传统的Spring应用需要一个外部的服务器,如Tomcat或Jetty。但Spring Boot提供了内置的Tomcat、Jetty和Undertow服务器,无需额外配置,你可以快速启动应用。 -
生态系统集成
Spring Boot与Spring生态系统中的其他项目如Spring Data, Spring Security等有很好的集成。只需几行配置,你就可以集成多个Spring项目。 -
生产力和速度
Spring Boot旨在提高开发速度,减少开发者在配置和引导应用上所花费的时间。通过提供各种生产级的功能,如健康检查和外部配置,Spring Boot确保应用是生产就绪的。
总结:Spring Boot并不是替代Spring,而是建立在Spring之上,提供了更快、更简单的方式来构建、部署和运行Spring应用。它解决了传统Spring应用中的许多常见问题,并提供了一个简化的开发模式,使得开发者可以更专注于代码的编写,而不是配置和设置。
简单介绍一下 Spring?有啥缺点?
Spring 是重量级企业开发框架 Enterprise JavaBean(EJB) 的替代品,Spring 为企业级 Java 开发提供了一种相对简单的方法,通过 依赖注入 和 面向切面编程 ,用简单的 Java 对象(Plain Old Java Object,POJO) 实现了 EJB 的功能
虽然 Spring 的组件代码是轻量级的,但它的配置却是重量级的(需要大量 XML 配置)。
为此,Spring 2.5 引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式 XML 配置。Spring 3.0 引入了基于 Java 的配置,这是一种类型安全的可重构配置方式,可以代替 XML。
尽管如此,我们依旧没能逃脱配置的魔爪。开启某些 Spring 特性时,比如事务管理和 Spring MVC,还是需要用 XML 或 Java 进行显式配置。启用第三方库时也需要显式配置,比如基于 Thymeleaf 的 Web 视图。配置 Servlet 和过滤器(比如 Spring 的DispatcherServlet)同样需要在 web.xml 或 Servlet 初始化代码里进行显式配置。组件扫描减少了配置量,Java 配置让它看上去简洁不少,但 Spring 还是需要不少配置。
光配置这些 XML 文件都够我们头疼的了,占用了我们大部分时间和精力。除此之外,相关库的依赖非常让人头疼,不同库之间的版本冲突也非常常见。
为什么要有 SpringBoot?
Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot 旨在简化 Spring 开发(减少配置文件,开箱即用!)。
说出使用 Spring Boot 的主要优点
Spring Boot 项目所需的开发或工程时间明显减少,通常会提高整体生产力。
Spring Boot 不需要编写大量样板代码、XML 配置和注释。
Spring 引导应用程序可以很容易地与 Spring 生态系统集成,如 Spring JDBC、Spring ORM、Spring Data、Spring Security 等。
Spring Boot 遵循“固执己见的默认配置”,以减少开发工作(默认配置可以修改)。
Spring Boot 应用程序提供嵌入式 HTTP 服务器,如 Tomcat 和 Jetty,可以轻松地开发和测试 web 应用程序。(这点很赞!普通运行 Java 程序的方式就能运行基于 Spring Boot web 项目,省事很多)
Spring Boot 提供命令行接口(CLI)工具,用于开发和测试 Spring Boot 应用程序,如 Java 或 Groovy。
Spring Boot 提供了多种插件,可以使用内置工具(如 Maven 和 Gradle)开发和测试 Spring Boot 应用程序。
什么是 Spring Boot Starters?
Spring Boot Starters 是一系列依赖关系的集合,因为它的存在,项目的依赖之间的关系对我们来说变的更加简单了。
举个例子:在没有 Spring Boot Starters 之前,我们开发 REST 服务或 Web 应用程序时; 我们需要使用像 Spring MVC,Tomcat 和 Jackson 这样的库,这些依赖我们需要手动一个一个添加。但是,有了 Spring Boot Starters 我们只需要一个只需添加一个spring-boot-starter-web一个依赖就可以了,这个依赖包含的子依赖中包含了我们开发 REST 服务需要的所有依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具