目录
什么是ConcurrentHashMap?_GuGuBirdXXXX的博客-CSDN博客
从ConcurrentHashMap缓存中获取Bean的流程
单例bean(singleton)与原型bean(prototype)【多例】的区别
BeanFactory和ApplicationContext有什么区别
事务+分布式事务【2023面试题】_seata面试题_MXin5的博客-CSDN博客
说下Spring框架的组成
-
CoreContain核心容器模块:
-
-
spring-core:提供框架的基本组成部分,包括 IoC 和依赖注入功能
-
spring-beans:提供 BeanFactory,工厂模式
-
context:提供国际化,事件传播,资源加载等功能
-
spring-ExpressionLanguage:提供表达式语言
-
-
Web模块
-
-
Web:提供面向web的基本功能和面向web的应用上下文
-
Web-MVC:为web应用提供模型视图控制(MVC)
-
Web-Socket:在 web 应用程序中提供客户端和服务器端之间通信的方式
-
Web-Portlet:模块提供了用于Portlet环境的MVC实现
-
-
数据/集成模块
-
-
JDBC:包含了Spring对JDBC数据访问进行封装的所有类
-
ORM:为对象-关系映射提供交互层
-
OXM:提供对Object/XML映射实现的抽象层
-
JMS:主要包含了一些制造、消费和消息的功能
-
Transaction:为实现特殊接口类以及所有的 POJO 支持编程式和声明式的事务管理
-
-
其他模块
-
-
AOP:提供了面向切面编程相关实现
-
Aspects:模块提供了与AspectJ的集成,是一个功能强大的AOP框架
-
Instrumentation:提供了class instrumentation 的支持和类加载器classloader的实现
-
Messaging:为 STOMP 提供支持
-
Test:支持使用JUnit和TestNG对Spring组件进行测试
-
Spring的优点
1,方便解耦,简化开发【将创建对象和依赖关系交给Spring容器进行管理】:
通过spring提供的IOC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免原编码所造成过度程序耦合;有了spring,用户不再为了单列模式类,属性文件解析等这些很底层的需求编写代码,可以专注于上层的应用的
2,AOP编程的支持【增加新的功能-事务、异常的统一处理、日志】:
通过spring提供的AOP功能方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付.spring的AOP支持允许将一些通用任务如安全,事务,日志等进行集中式管理,从而提供了更好的复用
3,声明事务的支持【直接使用注解@Transactional】:
在spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明方式灵活地进行事务的管理,提高开发效率和质量
4,方便程序的测试【支持Junit4】:
可以用非容器依赖编程方式进行几乎所有的测试工作,在spring里,测试不在是昂贵的操作,而是随手课做的事情没列入spring对junit4支持,可以通过注解方便的测试spring程序
5,方便集成各种框架:
spring不排斥各种优秀的开源框架,相反,spring可以降低各种框架的使用难度,spring提供了对各种哟毓秀框架(如Strust,Hibernate,Hessian,Quartz)等的直接支持.
6,降低javaEE API的使用难度:
spring对很多难用的java EE API(如JDBC,javaMail,远程调用等)提供了一个薄薄的封装层,通过spring的简易封装,这些java EE API的使用难度大大降低.
什么是Spring
Spring是一个开源的轻量级基于控制反转【IOC-Inversion Of Control--思想,DI依赖注入是实现】和面向切面编程【Aop-Aspect-oriented programming】的容器框架。轻量级是说它开发使用简单,功能强大。
SpringIOC
控制反转【Inversion of Control】,将对象的创建和依赖关系交给Spring容器进行管理,而不是由程序员进行完成。IOC的核心就是依赖注入(Dependency Injection,简称DI),通过DI可以将某个Bean所依赖的其他Bean实例注入到该Bean中,这样的好处就是降低了Bean之间的耦合性,使程序更加灵活、可维护性高。--比如UserController类中注解注入UserSerive对象。
SpringIOC底层原理
1在配置文件中定义一个Bean
2加载Spring的配置,并对xml进行解析。
3针对Bean的定义属性,会创建一个对象BeanDefination(注意不是Bean实例)
4存储多个BeanDefination(Bean的定义对象)
要用ConcurrentHashMap<String,BeanDefination>装起来,Bean的注册。
【因为基本上使用在多线程的环境中,读取的性能就会更高--JDK1.8过后采用的数据+链表+红黑树存储】环境中,使用ConcurrentHashMap依赖于他的特性,查询效率就会更高。
5如果是单例的,【默认是饿汉,在Bean注册完成之后(4步)就会去concurrentHashMap拿到BeanDefination,根据BeanDefination
使用反射或代理的方式进行创建真正的实例对象。】第一次使用的时候进行创建
6接下来就是对Bean进行初始化,以及属性注入。
7将创建好的Bean存储在另外一个ConcurrentHashMap<String,BeanWrapper>
8使用的时候直接去ConcurrentHashMap中取,根据Id(name)类型获取Bean。【@Autowired通过类型注入,类型没有就会采用名字注入,@Resources通过名字进行注入】。
什么是ConcurrentHashMap?_GuGuBirdXXXX的博客-CSDN博客
当Spring启动时,IOC容器会加载Spring的配置文件,包括XML配置或者注解,然后解析这些Bean并把相关定义信息封装成BeanDefinition对象,通过Bean注册器BeanDefinitionRegistry注册到IOC容器,也就是一个ConcurrentHashMap中
此时会找出所有的单例且非懒加载的bean,根据其BeanDefinition进行Bean的实例化,它会判断如果bean中有方法覆盖,就使用JDK反射创建Bean,否则使用CGLIB动态代理方式生成代理。然后把实例化好的Bean缓存到一个ConcurrentHashMap中
==========================底层比较重要的类=================================
BeanFactory:创建Bean的工厂,提供了基本的获取Bean的方法
ApplicationContext:是BeanFactory的子接口,功能增强了如读取Resources,对消息的支持,如国际化支持等
ClasspathXmlApplicationContext:是ApplicationContext的子实现,可以自动从ClassPath类路径下加载xml配置,然后完成IOC的启动【getBean,getType】
AnnotationConfigApplicationContext:是针对注解配置的IOC容器,在SpringBoot中使用
XmlWebApplicationContext:是Spring整合了SpringMVC,在Web环境中使用的IOC工厂
什么是循环依赖?
循环依赖:指的是两个或多个对象之间相互持有对象作为依赖,形成一个循环依赖的关系。
举例:比如A类中有B属性(成员变量),B类中有A属性,
这样子就造成了spring在实例化其中一个类A的时候,A中所依赖的B还没有实例化,这个时候就要去实例化类B,而实例化类B的时候又发现B依赖了A类,导致循环引用,无限创建。
Spring中有哪些循环依赖?
1.构造器注入循环依赖
2.setter方法 注入循环依赖
3.单例Bean之间的循环依赖
1.构造器注入循环依赖
构造器注入循环依赖是指两个或多个 bean 通过构造器互相依赖。例如:
@Component
public class A {
private final B b;
@Autowired
public A(B b) {
this.b = b;
}
}
@Component
public class B {
private final A a;
@Autowired
public B(A a) {
this.a = a;
}
}
在这个示例中,A
和 B
通过构造器互相依赖,Spring 会尝试使用构造器注入来解决循环依赖,但如果无法解决,会抛出异常。
2.setter 注入循环依赖
属性的setter方法循环依赖是指两个或多个Bean之间通过setter方法互相依赖。例如:
public class A {
private B b;
public void setB(B b) {
this.b = b;
}
}
public class B {
private A a;
public void setA(A a) {
this.a = a;
}
}
在这个例子中,A和B之间存在setter方法循环依赖。当Spring容器在初始化A时,需要初始化B,而初始化B时又需要初始化A,因此会导致循环依赖。
解决方法:使用构造方法注入,或者使用属性注入时使用延迟加载。
- 属性的setter方法循环依赖的解决方法示例:
public class A {
private B b;
public A() {
}
// 使用构造方法注入B
public A(B b) {
this.b = b;
}
// 使用setter方法注入B
public void setB(B b) {
this.b = b;
}
}
public class B {
private A a;
public B() {
}
// 使用构造方法注入A
public B(A a) {
this.a = a;
}
// 使用setter方法注入A
public void setA(A a) {
this.a = a;
}
}
// 在配置文件中进行Bean的声明和注入
@Bean
public A a() {
return new A(b());
}
@Bean
public B b() {
B b = new B();
b.setA(a());
return b;
}
3.单例Bean之间循环依赖
单例Bean之间循环依赖是指两个或多个单例Bean之间存在相互依赖。例如:
@Service
public class A {
@Autowired
private B b;
}
@Service
public class B {
@Autowired
private A a;
}
在这个例子中,A和B之间存在单例Bean循环依赖。当Spring容器在初始化A时,需要初始化B,而初始化B时又需要初始化A,因此会导致循环依赖。
@Service
public class A {
@Autowired
private B b;
public void methodA() {
b.methodB();
}
}
@Service
public class B {
@Autowired
private A a;
public void methodB() {
a.methodA();
}
}
// 在配置文件中进行Bean的声明和注入
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public A a() {
A a = new A();
a.setB(b());
return a;
}
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public B b() {
B b = new B();
b.setA(a());
return b;
}
解决循环依赖的方法
使用'@Lazy'注解
延迟初始化bean,解决单例Bean注入或 setter 注入的循环依赖问题。
@Component
public class A {
private final B b;
@Autowired
public A(@Lazy B b) {
this.b = b;
}
}
@Component
public class B {
private final A a;
@Autowired
public B(@Lazy A a) {
this.a = a;
}
}
Spring为什么解决不了多例和构造器的循环依赖?
Spring中利用缓存机制解决循环依赖问题,核心是利用一个map。来解决这个问题,这个map就是缓存。
为什么可以这么做,因为我们的Spring创建的bean是默认单例的,而且是字段注入(setter注入)的,单例意味着只需要创建一次对象,然后将创建的对象存储到缓存中,后面就可以从缓存中取出来。
如果是原型bean,那么就意味着每次都要去创建对象,无法利用缓存; 如果是构造方法注入,那么就意味着需要调用构造方法注入,也无法利用缓存。
Spring解决循环依赖使用的三级缓存
-
一级缓存(singletonObjects):用来存放已经(创建)实例化好的单例bean对象,即单例Bean缓存池
-
二级缓存(earlySingletonObjects):用于存放早期暴露出来的单例对象,这些对象是不完整的,通过提前暴露用来解决循环依赖的问题。用来缓存正在创建的bean对象。
-
三级缓存(SingletonFactories):用来存放创建Bean的工厂
Spring如何解决Bean的循环依赖的执行流程
假设有两个bean,A依赖B,B依赖A
Spring容器启动时,先创建Bean对象A。
根据Bean对象A的依赖关系,在singletonObjects缓存【一级缓存】中对Bean对象A进行初始化,如果当前需要注入的Bean对象B在singletonObjects【一级缓存】中已经存在,则直接返回该对象,不需要再次创建。
如果Bean对象B对象不在singletonObjects【一级缓存】中,会将Bean对象A存放在二级缓存中,然后检查earlySingletonObjects【二级缓存】中是否包含Bean对象B,如果包含则直接返回该对象,否则会去三级缓存进行创建一个新的Bean对象B并放入earlySingletonObjects【二级缓存】缓存中,这时候就可以对Bean对象A注入Bean对象B了。
创建过程中,如果出现循环依赖情况【就是创建Bean对象B的时候发现依赖了Bean对象A】,则直接去一级缓存或二级缓存进行查找,查找到了就直接返回该对象实现注入,否则使用三级缓存进行创建Bean对象并存放在二级缓存中。
Bean对象A创建完成后,放入singletonObjects【一级缓存】中,并从earlySingletonObjects【二级缓存】和singletonFactories缓存【三级缓存】中删除该对象。
从ConcurrentHashMap缓存中获取Bean的流程
Spring在获取Bean实例时首先会尝试从一级缓存中获取。就会走二级缓存尝试获取,如果也没有,就会走三级缓存singletonFactories查找该Bean,如果找到则通过创建工厂来创建Bean实例对象。如果在走三级缓存singletonFactories中没有找到对应的Bean,则返回null,表示当前Bean没有被创建过。
SpringAOP
面向切面编程【AOP-Aspect-Oriented Programming】是一种编程规范,他的目的是将与业务无关的代码从业务代码中分离出来,使代码更加的简洁,清晰。比如事务,日志,异常处理等。在Spring中,AOP的主要作用就是在不改变原生类原有业务代码的情况下,给原生类进行功能的增强。就是严格遵守了OCP原则(面向扩展开放,面向修改封闭)。
下面是一个简单的Spring AOP的Java代码例子:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.impl.UserService.*(..))")
public void beforeMethod() {
System.out.println("beforeMethod:");
}
}
在这个例子中,我们定义了一个切面(LogAspect),使用@Aspect标注该类为切面,使用@Before注解标注切面执行的位置。在这里,@Before注解的参数表达式表示:对于com.example.service.impl包中的UserService的任何方法执行前,都会执行LogAspect类中的beforeMethod()方法。
当UserService被调用时,Spring AOP框架将检查其是否匹配该切面(LogAspect),如果匹配,则会执行该切面方法beforeMethod()。在执行方法之前,可以做一些日志记录、安全检查、权限控制等操作,以提高应用系统的健壮性和安全性。
SpringAOP实现原理
AOP的实现原理是基于动态代理,动态代理就是在运行时期,动态的为原生类生成一个代理类,该代理类中将原生类当作自己的成员变量,然后调用原生类的方法,然后在方法之前和方法之后加上需要增加的功能,从而实现对原生类的一个功能增强。
动态代理分为JDK动态代理和CGLIB动态代理,CGLIB代理需要导入相关的jar包,两者的区别是JDK动态代理要求目标类需要实现至少一个接口。而CGLIB则是基于继承进行代理,不需要实现任何接口。
Spring中默认采用JDK动态代理(代理类和目标对象(原生类)实现了相同的接口),如果目标对象没有实现任何接口,Spring会选择CGLIB动态代理(代理类通过继承原生类),或者你可以在配置文件中强制指定使用CGLIB代理。
常用设计模式+代理模式【Design Pattern】【我终于懂设计模式了】_GuGuBirdXXXX的博客-CSDN博客
AOP的设计模式
SpringAOP就是采用的是代理模式中的动态代理模式。 代理模式:动态的为原生类生成一个代理类,该代理类中将原生类当作自己的成员变量,然后调用原生类的方法,然后在方法之前和方法之后加上需要增加的功能,从而实现对原生类的一个功能增强。【遵守OCP原则】
代理模式分为静态代理和动态代理。
静态代理:手写的增强代码可以理解为静态代理。
动态代理:JDK动态代理和cglib动态代理
JDK动态代理【必须要实现接口】(给你生成一个兄弟,你的功能你兄弟也有,并且你兄弟还可以有其他的功能。)
必须需要实现接口--为什么要实现接口?
代理类和原生类需要实现相同的接口,从而具有相同的功能,JDK动态代理就是通过接口创建一个代理类,然后具有相同的接口功能,然后进行增强。
cglib动态代理--采用继承的方式【给你生成一个儿子】
代理对象(类)去继承目标对象(需要代理的类),而且可以进行重写和功能增强。
AOP案例【事务】
下面我们使用AOP来做一个事务管理案例:在每个Service方法执行前后添加事务的代码
1.创建一个普通类,这个类的方法需要有事务
@Service
public class UserServiceImpl implements IUserService {
public void insert() {
System.out.println("UserServiceImpl.insert:保存User...");
}
public void delete() {
System.out.println("UserServiceImpl.delete:删除User");
}
}
2.创建一个切面类(加上注解@Aspect表示这是一个切面类,@Component表示将这个类交给Spring容器进行管理),这个类里面提供公共的业务代码,即:事务代码
@Component
@Aspect
public class TranscationManager {
//定义切点,表达式作用于所有到service的所有的方法
@Pointcut("execution(* cn.xxx.*.service.*.*(..))")
public void pointcut(){}
//前置通知 , 方法执行前执行,用来开启事务
@Before("pointcut()")
public void begin(JoinPoint joinPoint){
System.out.println("TranscationManager.begin:开启事务...:");
}
//后置返回通知 ,方法正常返回后执行, 用来提交事务
@AfterReturning("pointcut()")
public void commit(){
System.out.println("TranscationManager.commit:提交事物...");
}
//后置异常通知,方法出现异常调用,用来回滚事务
@AfterThrowing(value = "pointcut()",throwing="e")
public void rollback(JoinPoint joinPoint,Throwable e){
System.out.println("TranscationManager.rollback:回滚事物咯...:"+e.getMessage());
}
//后置通知,不管方法会不会出现异常,都会执行,用来关闭资源
@After("pointcut()")
public void close(){
System.out.println("TranscationManager.close:关闭连接...");
}
//环绕通知,拦截原始类的类的方法,可以通过 joinPoint调用原始的类
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint){
return null;
}
}
3.配置Spring支持AOP注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--开启IOC注解支持-->
<context:component-scan base-package="cn.xx" />
<!--开启AOP注解支持,默认使用jdk动态代理,如果指定 proxy-target-class=true 则实例CGLIB代理-->
<aop:aspectj-autoproxy />
</beans>
4.测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application_aop.xml")
public class AopTest {
@Autowired
private IUserService userService ;
@Test
public void testAop(){
userService.insert();
System.out.println("=====================================");
userService.delete();
}
}
控制台效果
TranscationManager.begin:开启事务…: UserServiceImpl.insert:保存User… TranscationManager.commit:提交事物…
TranscationManager.close:关闭连接…
TranscationManager.begin:开启事务…: UserServiceImpl.delete:删除User… TranscationManager.commit:提交事物… TranscationManager.close:关闭连接…
Spring AOP里面的几个名词的概念:
(1)连接点(Join point):指程序运行过程中所执行的方法。在Spring AOP中,一个连接点总代表一个方法的执行。
(2)切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。
在Spring AOP中,切面可以在类上使用 @AspectJ 注解来实现。
(3)切点(Pointcut):切点用于定义 要对哪些Join point进行拦截。
切点分为execution方式和annotation方式。execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦截add、search。annotation方式可以指定被哪些注解修饰的代码进行拦截。
(4)通知(Advice):指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包括Around、Before、After、After returning、After throwing。
(5)目标对象(Target):包含连接点的对象,也称作被通知(Advice)的对象。 由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个代理对象。
(6)织入(Weaving):通过动态代理,在目标对象(Target)的方法(即连接点Join point)中执行增强逻辑(Advice)的过程。
(7)引入(Introduction):添加额外的方法或者字段到被通知的类。Spring允许引入新的接口(以及对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
说一下定义切面相关的注解
@Aspect切面:用来类上,代表这个类是一个切面
@Pointcut切点:定义切点 = cn.xx.service.*,在那个业务上运行
@Before:前置通知,在目标方法运行之前运行
@After:后置通知,在目标方法运行结束之后运行(无论方法正常结束还是异常结束)
@AfterReturning:返回通知,在目标方法正常执行返回之后运行
@AfterThrowing:异常通知,在目标方法出现异常以后运行
@Around:环绕通知
Spring框架用到了那些设计模式?
1.单例模式:Spring中的Bean默认是单例模式,只创建一次实例且在整个应用中共享。
2工厂模式:Spring中使用BeanFactory或者ApplicationContext作为工厂,生成指定Bean的实例,并交给Spring容器进行管理。
3代理模式:AOP底层实现就是用的代理模式,Spring通过代理模式实现对目标方法的增强。
等多种模式
单例bean(singleton)与原型bean(prototype)【多例】的区别
Bean默认是单例模式(singleton)【Spring为什么将bean默认设计成单例模式?--为了提高性能,减少bean对象的创建,能够快速从缓存中获取到bean,减少jvm垃圾回收所带来的新性能损耗】,在处理多次请求的时候Spring容器只会实例化一个bean对象,后续的请求都会公用这个bean对象。这个对象会保存在一个map里面,当有请求来的时候会先去缓存(map)中查找是否存在,如果有就直接使用,如果没有就实例化一个对象。所以这是单例的,对于原型bean(prototype多例)来说,每次请求都会创建一个新的实例化对象bean。
单例模式-懒汉模式【双重校验锁-解决线程安全问题和效率低】
单例模式-饿汉模式
测试类
什么是反射?【SpringAOP】
反射就是在程序运行的时候,通过获取类的字节码文件动态地去获取类中的信息(类的信息,方法信息,构造器信息,字段等信息),并映射成一个个对象。
以下是Java代码举例:
// 通过全限定路径名获取类的Class对象
Class<?> clazz = Class.forName("java.lang.String");
// 创建一个对象
Object obj = clazz.newInstance();
// 获取方法并调用
Method method = clazz.getMethod("equals", Object.class);
boolean result = (boolean) method.invoke(obj, "test");
// 获取字段并设置值
Field field = clazz.getDeclaredField("value");
field.setAccessible(true);
char[] newValue = {'t', 'e', 's', 't'};
field.set(obj, newValue);
// 获取构造函数并创建实例
Constructor<?> constructor = clazz.getConstructor(String.class);
Object newObj = constructor.newInstance("test");
这段代码通过反射机制获取String类的Class对象,然后通过newInstance方法创建一个字符串对象。接着获取equals方法并调用,设置字段value的值,以及获取构造函数并创建实例。这些操作都是在程序运行时进行的,可以根据不同的需求进行动态地操作对象。
为什么需要使用反射?
反射是框架的灵魂,增加了程序的灵活性和减少了代码的重复性,避免将程序写死在代码里(解决硬编码问题),
举一个具体的例子:
假设我们需要设计一个通用的日志模块,可以记录调用类的名称、方法名称和参数,我们可以使用反射机制来实现这个功能。
如果不使用反射,我们需要在每个类中手动的记录方法的调用信息,而这将非常麻烦。比如下面的例子:
public class MyService {
public void doSomething(Object arg) {
System.out.println("MyService.doSomething(" + arg + ")");
// ...
}
}
如果我们同时存在多个类似的方法,将会极大地增加维护的复杂度。使用反射,我们只需要在日志模块中预定义好调用方法的信息,具体的调用过程可以通过反射机制来完成,代码如下所示:
public class LogUtil {
public static void log(Class<?> clazz, Method method, Object... args) {
String msg = clazz.getName() + "." + method.getName() + "(";
for (int i = 0; i < args.length; i++) {
msg += args[i];
if (i < args.length - 1) {
msg += ", ";
}
}
msg += ")";
System.out.println(msg);
}
}
public class MyService {
public void doSomething(Object arg) {
LogUtil.log(MyService.class, getClass().getMethod("doSomething", Object.class), arg);
// ...
}
}
通过使用反射,我们可以减少代码的重复性和维护性,并且提高了程序的灵活性。同时,这种方式也增加了程序的复杂度,所以需要根据具体的场景来权衡使用反射的好处和风险。
Spring AOP 和 AspectJ的区别
springAOP 是spring支持的面向切面AOP 编程。
AspectJ是一个面向切面的框架,语法简单。它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
然后SpringAOP就借助了AspectJ的语法风格开发出了属于自己的aspectJ。
什么是Spring Bean?
Spring Bean是Spring中最基本的组成单元(也是非常重要的部分),官方文档中的解释:在Spring中,构成应用程序主干【我们的程序是由一个个Bean构成的】,由Spring容器进行管理的对象称为Bean。
Spring的Bean懒加载和非懒加载有什么区别
Spring默认是单例的,然后是迫切加载。
懒加载:Spring容器启动时不会进行创建,需要使用bean对象的时候才创建,执行效率降低了,但节省资源,但不利于提前发现错误。
非懒加载,也叫迫切加载,Spring容器启动时就创建bean对象,执行效率提高了,但消耗资源,但有利于提前发现错误。
spring中默认是迫切加载,即在项目启动时,spring会扫描注解下的所有bean对象注入到IOC容器中进行管理。
如果需要懒加载,可以使用@Lazy注释或者xml中配置属性default-lazy-init="true"
实例化和初始化的区别
类的实例化:是指创建一个对象的过程,可以通过new和通过反射机制等方式实现。这个过程中会在堆中开辟内存,将一些非静态的方法,变量存放在里面。在程序执行的过程中,可以创建多个对象,既多次实例化。每次实例化都会开辟一块新的内存。
类的初始化:指的是在对象实例化后,进行一些必要的设置和处理的过程。在Spring中,Bean的初始化阶段是在实例化和属性赋值之后进行的。在这个阶段,静态的(变量,方法,代码块)会被执行。同时在会开辟一块存储空间用来存放静态的数据。初始化只在类加载的时候执行一次。
Spring Bean的生命周期?
从宏观的角度来说,Bean的什么周期可以分为五个阶段:
-
Bean的实例化(实例化对象)
-
Bean的属性注入(对象的属性注入)
-
Bean的初始化
-
Bean的就绪
-
Bean的销毁(Spring容器关闭时,容器中的Bean对象会被销毁,释放所占有的资源)
把对象交给Spring容器进行管理的注解有那些?
@Controller @Service @Component @Repository(持久化层注解) @Bean @RestController=@Controller+@ResponseBody
@ResponseBody的作用:一般是方法上获取或者类上,将方法的返回值(java对象)转换成json格式的数据。
json格式的好处就是可以直观的看到返回的java对象中的数据,
不用@responseBody的话返回的就是一个Object对象。
Spring的依赖注入bean的方式有哪些
1.注解注入:@Autowired @Resources
@Autowired注解和@Resource(通过名字byName进行注入)注解的作用相同,
@Autowired按照byType(通过类型)注入,如果@Autowired想使用名称可以结合@Qualifier注解进行使用
2.构造方法注入
3.通过setter方法注入
Spring 注入 Bean 的七种方式code小生的博客-CSDN博客
@Autowired和 @Resource的区别?
@Autowired和@Resource都是在Spring框架下,用于实现依赖注入的注解。
Autowired默认是以类型进行注入的(byType)。
如果需要按照名字(byName,比如将名称为UserMapper01的bean注入匹配的话,可以使用@Qualifier注解与@Autowired结合使用。
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("userDao")
private UserDao userDao;
// 业务方法
// ...
}
@Resource默认是按照名字自动注入(byName)。
@Component
public class User {
@Resource
private UserService userService;
//其他属性和方法
// ...
}
Bean的四种注册【创建】方式
Spring创建Bean的四种方式_快敲代码去的博客-CSDN博客
创建Bean其实就是创建对象。
方式一:普通注册方式,直接通过class注册
方式二:简单静态工厂方式注册
方式三:简单实例工厂方式注册
方式四:FactoryBean方式注册
Spring常用注解
创建对象(注入对象)的注解:@Controller(控制层的注解) @Service(业务逻辑层的注解) @Component(普通类的注解) @Repository(持久层的注解) - 要求:扫描包路径
注解注入的注解:@Autowired(先以类型进行匹配,类型相同再匹配变量名) @Resource(以名字进行匹匹配)
匹配请求的注解:@RequestMapping - 要求:开启Spring对Mvc的注解支持
响应json格式的注解:@ResponseBody -将当前方法的返回值转成json格式的字符串进行返回,而且不会经过视图解析器。
@ResponseBody // 加了这个才不会进入视图解析器(前端配置文件springmvc.xml) 才不会加上前缀和后缀
// 作用:将当前方法的返回值转换成json格式的字符串,并响应给调用方【如果是浏览器调用,就响应给浏览器】
// 如果是ajax异步调用,就会响应回调函数
要求:需要导入jackson的三个jar包 - 不导包会出现406
注解的注解,称为[元注解]
@Target(ElementType.TYPE)注解可以声明在哪些目标元素之前【类上,方法上】 @Retention(RetentionPolicy.RUNTIME)注解类的生命周期
Spring的Bean的作用域有那些?
Spring中为Bean定义了5种作用域,分别为Singleton(单例),prototype(多例),request(请求),session(会话)和global session(全局会话)。
singleton:单例模式,SpringIOC容器只会创建一个bean对象。
prototype:多例模式,每次请求访问spring容器时都会创建一个新的bean实例对象。
request:每次HTTP请求都会创建一个新的Bean,作用域绑定到HTTP请求的生命周期。
session:在一个HTTP Session中,为每个会话创建一个bean实例。与请求作用域的范围不同,会话作用域在整个会话的生命周期中持续存在,直到会话销毁。
globalSession: 同一个全局session共享一个Bean,一般用于portlet应用环境,该作用域仅适用于webApplicationContext环境.
BeanFactory和ApplicationContext有什么区别
BeanFactory【Bean工厂】
是IOC容器的核心接口,是一个Bean的工厂,采用的是延迟加载,在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)进行生产并且管理的。
ApplicationContext接口是BeanFactory接口的子接口,采用的是迫切加载。
除了继承BeanFactory中所有管理bean的方法,还拥有环境、国际化、资源、事件传播等服务相关的接口
BeanFactory是延迟加载,ApplicationContext【应用上下文】是迫切加载
BeanFactory延迟加载:
使用时才进行加载。
延迟加载的好处:当为了追求传输效率就会需要什么就再去创建什么时,就会体现出延迟加载的好处
ApplicationContext【应用上下文】迫切加载:
在启动项目创建上下文环境的时候就创建了Bean对象
配置一:让所有Bean都变成懒加载,配置default-lazy-init="true"
配置二:让其中一个指定的Bean变成懒加载,配置lazy-init="true"
Spring是如何管理事务的?
Spring事务管理详解程序员老石的博客-CSDN博客spring事务管理
Spring管理事务的两种方式---1编程式事务管理,2声明式事务管理
1编程式事务管理
指的是直接使用事务管理的API手动写代码来控制事务的启动、提交或回滚等操作,代码的耦合度比较高,使用的很少。
2声明式事务管理
声明式事务是通过注解@Transactional实现,无需任何配置。原理就是利用Spring框架的AOP的方式自动完成开启事务,提交事务,回滚事务,回滚的异常默认是运行时异常,可以通过rollbackFor的属性指定回滚的异常类型。