9 spring+mybatis+springmvc+常用的设计模式

spring

什么是反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

什么是spring

Spring 是个 java 企业级应用的开源开发框架。Spring 主要用来开发 Java 应用,但是有些扩展是针对构建 J2EE 平台的 web 应用。Spring 框架目标是简化 Java企业级应用开发,并通过 POJO 为基础的编程模型促进良好的编程习惯。

spring好处优势

1.轻量:Spring 是轻量的,基本的版本大约 2MB。

2.控制反转:Spring 通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。

3.面向切面的编程(AOP):Spring 支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
4.容器:Spring 包含并管理应用中对象的生命周期和配置。
5.MVC 框架:Spring 的 WEB 框架是个精心设计的框架,是 Web 框架的一个很好的替代品。
6.事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
7.异常处理:Spring 提供方便的 API 把具体技术相关的异常(比如由 JDBC,HibernateorJDO 抛出的)转化为一致的 unchecked 异常。

谈谈自己对于 Spring IOC 和 AOP 的理解

IOC

IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。

AOP

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码降低模块间的耦合度,并有利于未来的可拓展性和可维护性

在这里插入图片描述

如何理解 Spring 中的 AOP ?

在介绍 AOP 之前,我们先来了解一下 OOP 的概念。OOP 又指面向对象,它允许开发者定义纵向的关系,但并不适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。

AOP,又被称为面向切面,它是作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为切面(Aspect)。

AOP 减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。

AOP 实现的关键在于代理模式,AOP 代理主要分为静态代理和动态代理。静态代理的代表为AspectJ,而动态代理则以 Spring AOP 为代表。

AspectJ 与 Spring AOP 的区别?

  1. AspectJ 是静态代理的增强,所谓静态代理,就是 AOP 框架会在编译阶段生成 AOP 代理类,因此也称为编译时增强,它会在编译阶段将切面织入到 Java 字节码中,运行的时候就是增强之后的 AOP 对象。
  2. Spring AOP 使用的是动态代理,所谓的动态代理就是说 AOP 框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个 AOP 对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。(Spring AOP中的动态代理主要有两种方式, JDK 动态代理和 CGLIB 动态代理)

BeanFactory 和FactoryBean

BeanFactory 对底层的接口

表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂

是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中 XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。

BeanFactory和ApplicationContext就是spring框架的两个IOC容器,现在一般使用ApplicationContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。

BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。
原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来,

ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先

FactoryBean 一般这两个比没啥意义 这个也是个接口 就是个Bean

所有的bean都要有BeanFactory(也就是IOC容器)来进行管理。对于FactoryBean,是一个能生产或修饰对象生成的工厂bean,他的实现与设计模式中的工厂模式和修饰器模式类似。

FactoryBean可以说为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式

ApplicationContext继承了BeanFactory接口

应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;

  1. 国际化(MessageSource)

  2. 访问资源,如URL和文件(ResourceLoader)

  3. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

  4. 消息发送、响应机制(ApplicationEventPublisher)

  5. AOP(拦截器)

BeanFactory 和ApplicationContext区别

BeanFactory: 启动时候不会去实例化Bean, 去容器中拿bean的时候才会去实例化;也就是延迟实例化

优点:应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;

ApplicationContext:启动时候就会把所有的bean全部实例化。

优点:

1.所有的Bean在启动的时候都加载,系统运行的速度快;

2.在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题

3.建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)

ApplicationContext的三个实现类:

  1. ClassPathXmlApplication:把上下文文件当成类路径资源。
  2. FileSystemXmlApplication:从文件系统中的 XML 文件载入上下文定义信息。
  3. XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。

spring中bean的作用域有哪些

1.单例模式(spring默认机制)

<!--<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="狂神"/>-->
<bean id="user2" class="com.kuang.pojo.User" c:_0="狂神" c:_1="22" scope="singleton"/>

2.原型模式 每次从容器中get的时候,都会产生一个新对象!

<!--<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="狂神"/>-->
    <bean id="user2" class="com.kuang.pojo.User" c:_0="狂神" c:_1="22" scope="prototype"/>
  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。也就是单例模式。

  • prototype : 每次请求都会创建一个新的 bean 实例。

  • request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。

  • session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。

  • global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话

  • (1)singleton就是在创建起容器时(也就是加载spring配置文件的时候)就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。

    (2)当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。 在XML中将bean定义成prototype,可以这样配置:
    3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
    (4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
    (5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同

spring中bean的线程安全。

大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。

常见的有两种解决办法:

  1. 在Bean对象中尽量避免定义可变的成员变量(不太现实)。
  2. 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

bean生命周期(也就是bean的创建和销毁)

img

从创建对象到对象销毁的过程

①. 通过构造器或工厂方法创建 Bean 实例
②. 为 Bean 的属性设置值和对其他 Bean 的引用
③ . 将 Bean 实 例 传 递 给 Bean 前置 处 理 器 的 postProcessBeforeInitialization 方法
④. 调用 Bean 的初始化方法(init-method)
⑤ . 将 Bean 实 例 传 递 给 Bean 后 置 处 理 器 的 postProcessAfterInitialization 方法
⑦. Bean 可以使用了
⑧. 当容器关闭时, 调用 Bean 的销毁方法(destroy-method)

IOC创建对象的三种方式

  • 通过无参构造方法(需要用到无参构造和setter方法)
  • 通过有参构造(用到有参构造,不需要setter方法)
  • 通过工厂方法来创建对象,用的很少
1、调用无参构造
<bean id="user" class="edu.cloud.spring.entity.User"></bean>
2、调用带参构造
<bean id="user2" class="edu.cloud.spring.entity.User">
<constructor-arg value="tom" index="1"></constructor-arg>
<constructor-arg value="101" index="0"></constructor-arg>
</bean>
3、工厂创建对象
工厂类:非静态方法创建对象

装配bean和依赖注入

https://blog.csdn.net/qq_41738264/article/details/105533760

装配bean的三种方式及区别

创建应用对象之间协作关系的行为称为装配, 这也是依赖注入的本质.

Spring提供了3种装配机制, 它们分别为:

  • 在XML中进行显式配置
  • 在Java中进行显式配置
  • 隐式的Bean发现机制和自动装配

https://blog.csdn.net/dela_?t=1

依赖注入的四种方式

  • 构造器
  • setter方法
  • 静态工厂:通过调用工厂类中定义的静态 方法来获取 对象
  • 实例工厂:获取对象实例的方法是非静态的
1、通过构造
<bean id="user2" class="edu.cloud.spring.entity.User">
<constructor-arg value="tom" index="1"></constructor-arg>
<constructor-arg value="101" index="0"></constructor-arg>
</bean>
2、通过set方法对属性注入【常用】
<bean id="user4" class="edu.cloud.spring.entity.User">
<property name="id" value="110"></property>
<property name="name" value="hhh"></property>
</bean>

<!-- 不用value了,用rel把这个对象引用进来 -->  
<!-- 三层架构 依赖注入 -->
<!-- Action -->
<bean id="userAction" class="edu.cloud.second.UserAction">
<!-- property中的name指的是命名setter方法中的attribute部分:eg. setUserService() name为:userService -->
<property name="userService" ref="userService"></property>
</bean>

<!-- UserService -->
<bean id="userService" class="edu.cloud.second.UserService">
<!-- 不用value了,用rel把这个对象引用进来 -->
<property name="userDao" ref="userDao"></property>
</bean>

<!-- UserDao -->
<bean id="userDao" class="edu.cloud.second.UserDao"></bean>

<!-- 内部Bean -->
<bean id="userAction2" class="edu.cloud.second.UserAction">
<property name="userService">
<bean class="edu.cloud.second.UserService">
<property name="userDao">
<bean class="edu.cloud.second.UserDao"></bean>
</property>
</bean>
</property>
</bean>
3P名称空间,属性注入优化
xml头文件包含:xmlns:p="http://www.springframework.org/schema/p"
<!-- p:属性注入 -->
<bean id="user" class="edu.cloud.second.User" p:id="999" p:name="Jack"></bean>
<!-- p:set方法注入 ref 引用-->
<bean id="userDao" class="edu.cloud.second.UserDao"></bean>
<bean id="userService" class="edu.cloud.second.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction2" class="edu.cloud.second.UserAction" p:userService-ref="userService"></bean>

转配bean方式可以分为手动装配和自动装配:

手动装配分为基于java和xml

bean的自动装配的五种方式:

no:关闭自动装配,通过显示设置ref属性进行对象装配:

byName:

byType:

constructor:

autodetect:首先尝试constructor,再尝试byType

xml

正常方式:

<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="people" class="com.kuang.pojo.People" >
    <property name="name" value="zhenxing"/>
    <property name="dog" ref="dog"/>
    <property name="cat" ref="cat"/>
</bean>

byName

<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="people" class="com.kuang.pojo.People" autowire="byName"/>

byType

<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="people" class="com.kuang.pojo.People" autowire="byType"/>

javaConfig 使用注解自动装配

@Autowired pojo中的People里面

@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;

@Resource注解和@Autowired对比

@Resource是Java的注解,@Autowired是spring的注解

  • @Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。

@Resource装配顺序:

  • ①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

  • ②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。

  • ③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。

  • ④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

注解开发

@Component有几个衍生注解,我们在web开发中,会按照MVC三层架构分层!

  • dao [@Repository], 一般dao层习惯用这个注解 作为持久层操作数据库的bean来使用
  • service 【@Service】一般service层习惯用这个注解
  • controller 【@Controller】一般controller层用这个注解 会被spring-mvc框架所使用
  • @Component可以标注任意类为spring组件,如果一个bean不知道属于哪个层,可以使用@Component注解标注。
    controller和repository不能被代替

静态代理模式的好处:

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务

  • 公共也就就交给代理角色!实现了业务的分工!

  • 公共业务发生扩展的时候,方便集中管理!

    缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低。

动态代理(动态代理的关系是在运行期确定的)

静态代理缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类.同时,一旦接口增加方法,目标对象与代理对象都要维护。

解决办法:动态代理:其实动态代理和静态代理的思想是不变的,动态代理和静态代理的区别就是,动态代理不用我们去手编写代理类,在运行时,动态的在内存中生产代理类。(字节码对象级别的代理对象)。

动态代理的底层都是反射

  • 动态代理和静态代理角色相同
  • 动态代理的代理类是动态生成的,不是我们直接写好的。
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口–JDK动态代理
    • 基于类:cglib
    • Java字节码实现

通过接口InvocationHandler和类proxy

AOP两种代理方式

JDK动态代理:基于接口

CGLib动态代理:基于类

JDK只能为接口创建代理实例,对于没有通过接口定义业务方法的类,只能通过CGLib创建动态代理实现

JDK和CGLib动态代理区别

1、JDK动态代理具体实现原理:

通过实现InvocationHandler接口创建自己的调用处理器;

通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;

通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;

通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;

JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。

2、CGLib动态代理:

利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

3、两者对比:

JDK动态代理是面向接口的。

CGLib动态代理是通过字节码底层继承要代理类来实现,因此如果被代理类被final关键字所修饰,会失败。

4、使用注意:

如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制);

如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。

Spring 如何处理线程并发问题?

在一般情况下,只有无状态的 Bean 才可以在多线程环境下共享,在 Spring 中,绝大部分 Bean 都可以声明为 singleton 作用域,因为 Spring 对一些 Bean 中非线程安全状态采用 ThreadLocal 进行处理,解决线程安全问题。

AOP的五种类型:

前置通知,后置通知,成功通知,异常通知,环绕通知

Spring 框架中用到了哪些设计模式?

  1. 工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例
  2. 单例模式:Bean 默认为单例模式
  3. 代理模式:Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术
  4. 模板方法:用来解决代码重复的问题,比如 RestTemplate
  5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如 Spring 中 listener 的实现 – ApplicationListener

spring事务相关

什么是事务:

数据库操作的最小单元

事务四大特性 ;ACID

spring管理事务的方式

1.编程式事务管理

编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。

2.声明式事务管理 用的多

声明式事务又分为两种:

  1. 基于XML的声明式事务
  2. 基于注解的声明式事务

声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。
编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的编程方式。唯一不足的地方就是声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的,但是可以通过提取方法的方式完成声明式事务管理的配置。

spring有哪几种事务传播行为

支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,挂起存在的任何事务。
  • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
spring事务隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、不可重复读、幻读
  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是不可重复读、幻读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

springboot

自动装配原理

简洁版

面试官问你你可以这样说,springboot是通过main方法下的SpringApplication.run方法启动的,启动的时候他会调用refreshContext方法,先刷新容器,然后根据解析注解或者解析配置文件的形式注册bean,而它是通过启动类的SpringBootApplication注解进行开始解析的,他会根据EnableAutoConfiguration开启自动化配置,这个里面还有一句@Import(AutoConfigurationImportSelector.class), 里面有个核心方法getCandidateConfigurations会调用loadFactoryNames(获取所有的加载配置,实现在下面),根据classpash路径以MATA-INF/spring.factorces下面以什么什么EnableAutoConfiguration开头的key去加载里面所有对应的自动化配置,他并不是把这一百二十多个自动化配置全部导入,在他每个自动化配置里面都有条件判断注解(@ConditionalOn…可能是class,property),先判断是否引入相互的jar包,再判断容器是否有bean再进行注入到bean容器.
在这里插入图片描述

在这里插入图片描述

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

在这里插入图片描述
所有的自动配置类就都在这里。
思考个问题,为什么这么多的自动配置有的没有生效,需要导入对应的starter才有作用
在这里插入图片描述
public class SpringApplicationAdminJmxAutoConfiguration:
在这里插入图片描述

动手实现自己的starter

1、新建组件com-itpsc-service,组件只有一个service。
2、编写UserService类
3、打包发布组件到maven仓库
4、新建一个启动组件starter,这个start里面会引入service的依赖
5、编写自动配置类

@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(JmxAutoConfiguration.class)
@ConditionalOnClass()
public class UserAutoConfiguration {
    @Bean
    public UserService getBean(UserProperties userProperties) {
        //创建组件实例
        UserService userService = new UserService();
        ------
        return userService;
    }
}

6、配置spring.factories文件
在src/main/resources新建META-INF文件夹,在META-INF文件夹下新建spring.factories文件。配置内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.itpsc.spring.boot.starter.UserAutoConfiguration

7、打包发布starter

8、新建工程引入starter就可以了。

配置文件内容

这个核心依赖只是版本而已,需要哪一个还需要去pom去写
在这里插入图片描述
依赖版本:
在这里插入图片描述
在这里插入图片描述

主程序

springbootapplication

springbootapplication 标注这更是一个springboot的应用

- springbootconfiguration  //是个配置类
- enableautoconfiguration   //自动配置
  - @AutoConfigurationPackage
  - @Import(AutoConfigurationImportSelector.class)
- comonentscan      //

在这里插入图片描述
spring.factories

在这里插入图片描述
**springboot的所有自动配置都是在启动的时候扫描并加载:spring.factories 所有的自动配置类都在这里面,还要判断条件是否成立,只要导入对应的stater,就会有对应的启动器,有了启动器,我们自动装配就会失效,然后就配置 **

在这里插入图片描述

springmvc

什么是MVC

  • MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
  • 是将业务逻辑、数据、显示分离的方法来组织代码。
  • MVC主要作用是降低了视图与业务逻辑间的双向偶合
  • MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。

Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。

最典型的MVC就是JSP + servlet + javabean的模式。

springMVC原理图

面试回答:前端控制器接受用户的请求并拦截,根据对应的请求找到对应的Controller处理器,处理器调用业务层并返回信息给前端控制器,然后前端控制器调用视图解析器找到对应视图并将数据渲染

我们只需要做两个地方,controller业务层,视图返回的名字

下面是文字步骤说明:

1、用户发送请求到前端控制器(DispatcherServlet)。

2、前端控制器请求处理器映射器(HandlerMapping)去查找处理器(Handler),HandlerMapping根据请求url查找Handler。

3、HandlerExcution将解析后的信息传递给DispatcherServlet

4、前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler)。

5、Handler让具体的controller去执行,由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

6、处理器执行完给处理器适配器返回ModelAndView。

7、处理器适配器向前端控制器返回ModelAndView。

8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器去进行视图解析。

9、视图解析器向前端控制器返回View。

10、前端控制器对视图进行渲染。

11、前端控制器向用户响应结果。

在这里插入图片描述

springmvc工作原理

springmvc注解

1 @Controller

控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示
@Controller注解在类上,表明这个类是Spring MVC里的Controller,将其声明为Spring的一个Bean,Dispatch Servlet会自动扫描注解了此注解的类,并将Web请求映射到注解了@RequestMapping的方法上,需要注意的是,在Spring MVC声明控制器Bean的时候,只能使用@Controller。

2 @RequestMapping(就是访问路径和参数)

@RequestMapping注解是用来映射Web请求(访问路径和参数)、处理类和方法的。它可以注解在类和方法上。注解在方法上的@RequestMapping路径会继承注解在类上的路径,@RequestMapping支持Servlet的request和response作为参数,也支持对它们的媒体类型进行配置。

3 @ResponseBody 返回JSON数据

@ResponseBody支持将返回值放在response体内,而不是返回一个页面。我们很多机遇Ajax的程序,可以以此注解返回数据而不是返回页面;此注解可以放在返回值或者方法上。

4 @RequestBody 接收JSON数据

@RequestBody接收前端传来的实体,比如前端通过 JSON 提交传来两个参数 username 和 password,此时我们需要在后端封装一个实体来接收。在传递的参数比较多的情况下,使用 @RequestBody 接收会非常方便

在这里插入图片描述

5 @PathVariable 接收路径参数

@PathVariable 用来接收路径参数,如/news/001,可接收001作为参数,此注解放置在参数前。RestFul风格

在这里插入图片描述

6 @RestController

@RestController是一个组合注解,组合了@Controller和@ResponseBody,意味着当只开发一个和页面交互数据的控制的时候,需要使用此注解。 若没有此注解,要想实现上述功能,则需自己在代码中加@Controller和@ResponseBody两个注解。

7.@RequestParam
@RequestParam 注解顾名思义,也是获取请求参数的,上面我们介绍了 @PathValiable 注解也是获取请求参数的,那么 @RequestParam 和 @PathVariable 有什么不同呢?

在这里插入图片描述

在这里插入图片描述

spring用到的设计模式

单例模式 必须会写

在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。

使用单例模式的好处:

  • 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
  • 由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

饿汉式

// 饿汉式单例模式 静态变量
public class Hungry {
    public static void main(String[] args) {
        Hungry instance1 = Hungry.getInstance();
        Hungry instance2 = Hungry.getInstance();
        System.out.println(instance1 == instance2);
    }

    private Hungry(){

    }
    private final static Hungry HUNGRY = new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }
}

在这里插入图片描述

DCL懒汉式

package com.kuang.designModel.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * 用的时候再去加载 ->懒汉式单例
 */
public class LazyMan {

    private static boolean qinjiang = false;

	//构造器私有方法
    private LazyMan() {
        //此时反射不可能再破坏这个
        synchronized (LazyMan.class){
            if(qinjiang == false){
                qinjiang = true;
            }else {
                throw new RuntimeException("不要用反射破坏异常");
            }

        }

        System.out.println(Thread.currentThread().getName() + "ok");
    }
    private  volatile static LazyMan lazyMan;

    public static LazyMan getInstance(){
        //加锁
        //双重检测锁模式的 懒汉式单例 简称DCL
        if(lazyMan == null){
            synchronized (LazyMan.class){
                if(lazyMan == null){
                    lazyMan = new LazyMan();//不是原子型操作
                    /**
                     * 1.分配内存空间
                     * 2.执行构造方法,初始化对象
                     * 3.把这个对象指向这个空间
                     * 可能发生指令重排序  所以上面需要加volatile
                     */
                }
            }
        }

        return lazyMan;
    }

    //多线程并发
    public static void main(String[] args) throws Exception {
        Field qinjiang = LazyMan.class.getDeclaredField("qinjiang");
        qinjiang.setAccessible(true);
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);//无视构造器
        LazyMan instance = declaredConstructor.newInstance();

        qinjiang.set(instance, false);

        LazyMan instance1 = declaredConstructor.newInstance();

        System.out.println(instance == instance1);//false 所以反射可以破坏单例模式

    }
}

单例模式不安全,反射可以破坏
所以有了枚举枚举

/**
 * 静态内部类 实现
 */
public class Holder {
    private Holder(){

    }
    public static Holder getInstance(){
        return InnerClass.HOLDER;
    }
    public static class InnerClass{
        private static final Holder HOLDER = new Holder();
    }

    public static void main(String[] args) throws Exception {
        LazyMan instance = LazyMan.getInstance();
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance2 = declaredConstructor.newInstance();
        System.out.println(instance);
        System.out.println(instance2);
    }
}

原型模式Prototype

克隆

工厂模式

代理模式

静态代理
1.接口
2.真实角色
3.代理角色
4.客户端访问
代理模式可以使真是角色的操作更加纯粹,不用关注一些公共业务
公共也就交给了代理角色,实现了业务分工
公共业务发生拓展的时候,方便集中管理
缺点:

一个真是角色就会产生一个代理角色,开发效率变低。

动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口 -JDK动态代理
    • 基于类:cglib
    • java字节码实现

模板方法

Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。

适配器模式

在这里插入图片描述

mybatis

缓存

一级缓存

一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Mabits默认开启一级缓存。

二级缓存

二级缓存是mapper级别的,Mybatis默认是没有开启二级缓存的。

#{}和${}区别

#{}:SQL参数占位符替换为?,可以防止SQL注入,变量替换后,会自动加上单引号

${}:拼接符,不能防止SQL注入,变量替换后,不会加上单引号,也可以表示properties文件中的变量占位符

动态sql 都有哪些动态 sql?能简述一下动态 sql 的执行原理不?

答:Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能,Mybatis 提供了 9 种动态 sql 标签 trim|where|set|foreach|if|choose|when|otherwise|bind。

其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值