Spring框架
2023-04-24 19:35:11 18 举报
AI智能生成
登录查看完整内容
为你推荐
查看更多
spring框架
作者其他创作
大纲/内容
注解
启动过程
Spring Boot
Spring启动过程是[IOC]容器的启动过程,本质是创建和初始化bean工厂(BeanFactory).BeanFactory是Spring IOC的核心,Spring使用beanFactory来实例化,配置和管理bean。
对于web程序,IOC容器启动过程即是建立上下文的过程,web容器会提供一个**全局的servletContext上下文环境**。其启动过程主要包含三个类,**ContextLoaderListener,ContextLoader和XmlWebApplicationContext。**在web.[xml]中提供ContextLoaderListener上下文监听器,在web容器启动时,会触发容器初始化事件,**ContextLoaderListener会监听到这个事件,从而触发ContextInitialized方法完成上下文初始化,这个方法中调用父类ContextLoader的方法完成上下文初始化。**ContextLoader类中主要完成三件事:1)创建WebApplicationContext;2)加载对应的Spring配置文件中的bean;(refresh方法,完成bean的加载)3)将WebApplicationContext放入servletContext中。ContextLoaderListener监听器初始化完之后,开始初始化web.xml中配置的[servlet](https://so.csdn.net/so/search?q=servlet&spm=1001.2101.3001.7020),如DispatcherSevletContextLoaderListener监听器监听的是servletContext,当web容器初始化后,servletContext发生变化时,会触发相应事件。**触发的事件**ContextClosedEventContextRefreshedEventContextStartedEventContextStoopedEventRequestHandleEventSpring容器启动后会触发ContextRefreshedEvent事件,想要在某个类加载完毕是干某事,但用了Spring管理对象,这个类又引用了其他类,比较复杂,可以写一个类继承Spring的ApplicationListener监听并监控ContextRefreshedEvent事件。
子主题
循环依赖
Aware的作用
首先,创建 Bean 会经过一系列的步骤,主要包括:1、实例化 Bean 对象。2、设置 Bean 属性。3、如果我们通过各种 Aware 接口声明了依赖关系,则会注入 Bean 对容器基础设施层面的依赖。具体包括 BeanNameAware、BeanFactoryAware 和 **ApplicationContextAware**,分别会注入 Bean ID、Bean Factory 或者 ApplicationContext。4、调用 BeanPostProcessor 的前置初始化方法 postProcessBeforeInitialization。5、如果实现了 InitializingBean 接口,则会调用 afterPropertiesSet 方法。6、调用 Bean 自身定义的 init 方法。7、调用 BeanPostProcessor 的后置初始化方法 postProcessAfterInitialization。
创建
Spring Bean 的销毁过程会依次调用 DisposableBean 的 destroy 方法和 Bean 自身定制的 destroy 方法。
销毁
Singleton,这是 Spring 的默认作用域,也就是为每个 IOC 容器创建唯一的一个 Bean 实例。Prototype,针对每个 getBean 请求,容器都会单独创建一个 Bean 实例。从 Bean 的特点来看,Prototype 适合有状态的 Bean,而 Singleton 则更适合无状态的情况。另外,使用 Prototype 作用域需要经过仔细思考,毕竟频繁创建和销毁 Bean 是有明显开销的
作用域
bean的生命周期
@Controller注解注解的控制器可以同时支持处理多个请求动作
@RequestMapping(value=\"/hello\
路由
value
请求方法
method
发送的数据类型
consume
接收的数据类型
produce
指定request中必须包含某些特性的header值,才能让该方法处理请求
headers
@RequestMapping注释用来映射一个请求,用来处理类和方法发送请求动作
@RequestParam注解,该注解类型用于将指定的请求参数赋值给方法中的形参
@RequestHeader注解,该注解类型用于将请求的头的信息区域数据映射到功能处理方法的参数上。
@CookieValue注解,该注解类型用于将请求的Cookie数据映射到功能处理方法的参数上。
@Controller注解
@Service
@repository
处理request body部分的注解有:@RequestParam和@RequestBody
处理requet uri部分的注解有:@PathVaribale
处理request header部分的注解有:@RequestHeader和@CookieValue处理request header部分的注解有:@RequestHeader和@CookieValue
处理attribute类型的注解有:@SessionAttributes和@MoelAttribute
参数绑定的注解
@RestController注释不过是@Controller和@ResponseBody注释的组合
@Component
@FeignClient(\"stores\")
Open-Feign相关的注解
@Primary 设置高优先级注解
Qualifier 的意思是合格者,通过这个标示,表明了哪个实现类才是我们所需要的,添加 @Qualifier 注解,需要注意的是@Qualifier 的参数名称为我们之前定义 @Service 注解的名称之一。
@Resource和@Autowired都是做bean的注入时使用区别:(1)、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配(2)、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。@Resource和@Autowired都是做bean的注入时使用
Resource 注释标记了应用程序需要的资源。该注解可以应用于应用程序组件类,或组件类的字段或方法。当注解应用于字段或方法时,容器将在组件初始化时将所请求资源的实例注入到应用程序组件中。如果注释应用于组件类,则注释声明应用程序将在运行时查找的资源(1)、@Resource后面没有任何内容,**默认通过name属性去匹配bean**,找不到再按type去匹配(2)、指定了name或者type则根据指定的类型去匹配bean(3)、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource注解
@Resource和@Autowired注解
@Target(用于描述注解的适用范围 {被描述的注解可以用在什么地方})@Target说明了Annotation所修饰的对象范围:Annotation可用于 packages、type(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。 取值(ElementType)
@Target
@Retention表示需要在什么级别保存该注释信息,被描述的注解在什么范围内有效。 取值(RetentionPoicy):SOURCE|CLASS|RUNTIME
@Retention
@Documented 可以被例如 javadoc此类的工具文档化,Documented是一个标注注解,没有成员。
@Documented
@Inherited允许其他注解继承该注解。
@Inherited
元注解
Spring
#{}和${}的区别是什么?#{} 是预编译处理,${}是字符串替换。Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;Mybatis在处理${}时,就是把${}替换成变量的值。使用#{}可以有效的防止SQL注入,提高系统安全性。
#和$的区别
第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。第2种: 通过 `` 来映射字段名和实体类属性名的一一对应的关系。
当实体类中的属性名和表中的字段名不一样,怎么办?
第1种:在Java代码中添加sql通配符。第2种:在sql语句中拼接通配符,会引起sql注入
模糊查询like语句该怎么写?
Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。 Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中每个标签,都会被解析为一个MapperStatement对象。 Mapper接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回。
Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
Mybatis的一级、二级缓存
什么是SQL注入?
MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。
MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。
MyBatis如何防止SQL注入?
Mapper接口方法名和mapper.xml中定义的每个sql的id相同;Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;Mapper.xml文件中的namespace即是mapper接口的类路径。Mapper接口方法名和mapper.xml中定义的每个sql的id相同;
使用MyBatis的mapper接口调用时有哪些要求?
MyBatis
响应式编程
熔断
限流
Spring-Cloud-Gateway
jdk 动态代理
cglib动态代理
动态代理
AOP的原理
Transactional
首先从main找到run()方法,在执行run()方法之前new一个SpringApplication对象进入run()方法,创建应用监听器SpringApplicationRunListeners开始监听然后加载SpringBoot配置环境(ConfigurableEnvironment),然后把配置环境(Environment)加入监听对象中然后加载应用上下文(ConfigurableApplicationContext),当做run方法的返回对象最后创建Spring容器,refreshContext(context),实现starter自动化配置和bean的实例化等工作。
Spring Boot 启动流程
@SpringBootConfiguration
作用:扫描主配置类包的所有包下的类,相当于xml配置文件中的context:component-scan。eg:pojo中的User类
@ComponentScan
作用:开启自动装配类
@AutoConfigurationPackage:自动配置包
作用:通过import导入第三方提供的bean的配置类:AutoConfigurationImportSelector:给容器中导入组件
@Import(AutoConfigurationImportSelector.class)——核心注解
@EnableAutoConfiguration(重点!!!)
SpringBoot启动的时候通过@EnableAutoConfiguration注解找到META-INF/spring.factories文件中的所有自动配置类,并对其加载,这些自动配置类都是以AutoConfiguration结尾来命名的。它实际上就是一个JavaConfig形式的IOC容器配置类,通过以Properties结尾命名的类中取得在全局配置文件中配置的属性,如server.port。
1. Spring Boot在启动时扫描项目所依赖的JAR包,寻找包含spring.factories文件的JAR包,2. 然后读取spring.factories文件获取配置的自动配置类AutoConfiguration`,3. 然后将自动配置类下满足条件(@ConditionalOnXxx)的@Bean放入到Spring容器中(Spring Context)4. 这样使用者就可以直接用来注入,因为该类已经在容器中了。tip: starter需要的几个关键组成,1.Property文件读配置项,2.Service文件作为具体实现,3.AutoConfiguration文件用来注册需要的单例等,4.在META-INF/spring.factories下面声明org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.tian.MyTestAutoConfiguration
spring boot 自动装配
@Autowired 注解注入。另外也有 @Resource 以及 @Inject 等注解
注入方式简单:加入要注入的字段,附上@Autowired,即可完成。使得整体代码简洁明了,看起来美观大方。
属性注入
推荐使用注入的就是这种,现在很少使用这种注解方式,写起来麻烦,当初推荐Spring自然也有他的道理: 构造器注入参数太多了,显得很笨重,另外setter的方式能用让类在之后重新配置或者重新注入。
set 方法注入
构造器注入的方式,能够保证注入的组件不可变,并且确保需要的依赖不为空。此外,构造器注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。
1 依赖不可变属性使用final关键字修饰2 依赖不为空(省去了我们对null的检查)当要实例化类的时候,由于类已经实现了有参数的构造函数,所以不会调用默认构造函数,那么就需要Spring容器传入所需要的参数,所以就两种情况:1、有该类型的参数->传入,OK 。2:无该类型的参数->报错。所以保证不会为空,Spring不会传一个null进去如果使用field注入,缺点显而易见,因为你不调用将一直无法发现NPE的存在。3 完全初始化状态这个可以跟上面的依赖不为空结合起来,向构造器传参之前,要确保注入的内容不为空,那么肯定要调用依赖组件的构造方法完成实例化。而在Java类加载实例化的过程中,构造方法是最后一步(之前如果有父类先初始化父类,然后自己的成员变量,最后才是构造方法)。所以返回来的都是初始化之后的状态。4 避免循环依赖使用field注入可能会导致循环依赖,即A里面注入B,B里面又注入A:使用构造器注入,在spring项目启动的时候,就会抛出:BeanCurrentlyInCreationException如果是field注入的话,启动的时候不会报错,在使用那个bean的时候才会报错。5、总结保证依赖不可变(final关键字)保证依赖不为空(省去了我们对其检查)避免了循环依赖当有一个依赖有多个实现的使用,推荐使用field注入或者setter注入的方式来指定注入的类型
构造方法注入
注入方式:field注入、setter注入与构造器注入spring推荐使用setter方法和构造器注入Autowired的bean对象,因此IDEA等工具中私有属性使用Autowired注入会提示警告。setter方法和构造器注入的方式,可以让对象不依赖于spring而独立使用,更加灵活;私有属性则只能通过spring上下文自动注入,一旦注入失败,没有重新注入的方式。@Resource不能用于构造器注入
spring在向IOC容器中注入Bean的时候有3种注入方式
Spring是通过递归的方式获取目标bean及其所依赖的bean的;Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。
三级缓存法:递归过程中,获取引用bean时,会先尝试用singletonObjects集合中获取,获取到了就直接返回,获取不到的话,从下一个缓存MAP中获取,isSingletonCurrentInCreation方法,从earlySingletonObjects中获取,如果还没有,且allowEarlyRefrence为true,会尝试从singletonFactories中获取beanFactory,然后调用她的getObject方法。
spring boot 属性注入和构造器注入的区别
Spring
0 条评论
回复 删除
下一页