spring

1、什么是控制反转(IOC) 和依赖注入?

   IOC根据javase,我们直接在对象内部通过new进行创建对象,是程序主动去创建对象。而ioc是有个专门容器来创建这些对象。是ioc容器控制了对象,即控制权的转移,应用程序本身不负责依赖对象的创建和维护而是由外部容器负责创建和维护传统程序是我们在类内部主动创建依赖对象,导致类之间的高耦合。Ioc设计的好处是松耦合增加灵活性。Spring容器创建好对象,存储到一个容器里,需要使用对象的时候,直接从容器中取出需要的对象即可。

   IOC的原理:工厂模式加反射机制,根据配置文件给出的类名动态的生成对象,要生产的对象都在配置文件中给出定义。

   DI:依赖注入的方式:基于配置的形式注入依赖,基于注解的形式注入依赖。

基于配置:在xml文件中设置

基于注解:@Autowired 根据类型注入 ,  @Resource 根据名称注入

2、BeanFactoryApplicationContext什么区别?BeanFactory和FactoryBean的区别?

  前者基础类型的IOC容器,含有bean集合的工厂类,采用懒加载的形式,容器启动后不会创建bean对象,只有当使用某个bean时,才对该bean进行加载实例化ApplicationContext前者的基础上增加了更高级的功能,提供了如下功能:访问资源(url和文件比如其扩展ClassPathXmlApplicationContext),支持aop功能,事务处理,在容器启动时便完成了所有bean的创建(预加载)

  FactoryBean是一个特殊的Bean,它是一个工厂对象,用于创建和管理其他Bean的实例。

3、如何用注解的方式配置spring

  @Autowired注解的原理是反射,通过反射获取需要注入的bean

可以bean描述转移到组件类的内部,只需要在相关类、方法或者字段使用注解即可,注解注入将会被容器在xml注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。@controller,@Service都可以负责注册一个beanspring的上下文中。下面是几种重要的注解类型

Bean:注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。

@Bean和@Autowired区别:
bean注解用于在Spring上下文中注册Bean,而Autowried注解用于从Spring应用程序内容获取Bean并将其连接为另一个对象的依赖项,bean注解的方法如果有入参,则会从spring容器中根据类型注入
@Autowired 默认required属性值为true,即注入时,该bean必须已经初始化在spring容器中,否则注入失败

如果有多个地方注册@Bean(name="xxx") ,则只有第一个声明的地方会成功注册

@Autowired默认按照Bean的类型进行装配,如果发现找到多个bean,那么就会按照byName方式比对,byName是将bean单例池中的key(bean的名字)与被注入的成员变量的名称匹配,而不是与被注入的成员变量的类型匹配

eg:

interface A {
}
class a1 implements A {
}
class a2 implements A {
}

@Autowired A a1;
@Autowired A a2;

 

spring支持基于接口的直接注入:
@Autowired
private List<MyInterface> mylist; 这样可以把MyInterface的子类bean直接添加到了myList中,并且还可以用Order来指定添加顺序
@Autowired
private Map<String, MyInterface> map;也可以把接口的实现类注入到map中,key:bean名称,类名首字母小写。

 

@Autowired如果作用在构造器上,可以把构造器的入参注入到容器中

@Required:此注解用于bean的setter方法上。表示此属性是必须的,必须在配置阶段注入,否则会抛出BeanInitializationExcepion。@Qualifier此注解是和@Autowired一起使用的。使用此注解可以让你对注入的过程有更多的控制。

@Qualifier可以被用在单个构造器或者方法的参数上。当上下文有几个相同类型的bean,使用@Autowired则无法区分要绑定的bean,此时可以使用@Qualifier来指定名称。

@Component
public class User {
@Autowired
@Qualifier("address1")
private Address address;
}

容器一般都会在启动的时候实例化所有单实例bean。如果我们想要 Spring 在启动的时候延迟加载 bean,即在调用某个 bean 的时候再去初始化,那么就可以使用 @Lazy 注解。此注解只对单例bean有用

4、spring中service有多个实现类,怎么注入?

方法一:Controller中注入service的时候使用@Autowired自动注入,@Qualifier("beanId")来指定注入哪一个。

方法二:Controller中注入service的时候使用@Resource(type = 类名.class)来指定注入哪一个。

方法三:

a、每个service的impl都可以指定名称(使用@Service(“名称”)

b、Controller中注入service的时候使用名称来指定注入哪一个(使用@Resource(name="名称"))。

 4、Spring怎么解决循环依赖的问题?

通过下面的bean生命周期可以看出,spring先将bean对象实例化(依赖构造函数),然后再设置对象属性。所以spring先用构造器实例化bean对象,此时对象是不完整的因为还没有注入属性,spring将不完整的对象放到一个map中。比如此时A依赖B,B依赖A,则spring先创建A,把不完整的A放入map中,然后创建B的时候从map中得到不完整的A,则B创建完成。然后A就可以注入B了。

1)如果A和B都是构造器注入,比如public A(B b),public B(A a),则spring无法处理循环依赖。

2)如果一个是构造器注入,一个是set注入,则不一定能成功。比如A通过set注入B,B通过构造函数注入A,这种情况下循环依赖可以解决,具体流程和上面描述的一样。如果A通过构造器注入B,B通过set注入A,则无法解决循环依赖。因为A的构造器中有B,创建B时,map中没有A,所以B创建失败,则A也无法创建成功。

spring三级缓存是什么

 

一级缓存:存放完全初始化以后得bean
二级缓存:存放原始bean,并且存在尚未填充的属性
三级缓存:存放工厂对象,工厂对象的目的是生成bean实例
三级缓存的目的是解决循环依赖,在Bean的创建过程中,spring会适当的从这三个缓存中检索或者放入对象,确保即使存在循环依赖的情况下,也能成功的去创建和注入Bean

5、BeanFactory为例,说明一个bean的生命周期:

1)容器读取bean定义的文件,并生成bean的实例。
2)执行bean的静态变量或静态语句块,执行实例变量或初始化语句块,执行bean的构造函数,给bean设置一些属性。
3)接着会将所有标有@Autowired的属性全部注入到当前bean
4)如果有实例实现了BeanPostProcessor接口,则任何bean初始化之前都会回调这个实例的postProcessBeforeInitialization()方法,
5)  执行@PostConstruct注释的方法,注意@PostConstruct只有在spring环境中才有意义 否则不会执行
6)如果bean实现了InitializingBean接口,则会执行InitializingBean接口的afterPropertiesSet方法。
7)如果bean配置了init-method方法,则会执行init-method配置的方法
8)如果有实例实现了BeanPostProcessor接口,则任何bean都会执行这个实例的postProcessAfterInitialization()方法
9)如果bean配置了destory-method方法,则会执行destory-method配置的方法。至此整个bean的生命周期结束。

PostConstruct和afterPropertiesSet里的内容,只会在项目启动时执行

 

 6、spring框架中用到了哪些设计模式?

工厂模式:spring容器实例化bean用到了静态工厂模式,Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象

单例模式:spring配置文件中定义的bean默认为单例模式

适配器模式:如springmvc的HandlerAdapter。HandlerAdapter子类有很多,每一类型的controller有对应的适配器实现类,每类controller有不同的实现方式。Spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类,适配器代替 controller执行相应的方法。用到的是接口的适配器模式

代理模式:jdkcglib

模板模式:如spring的事务管理器:https://zhuanlan.zhihu.com/p/125534510。事务管理器抽象类的模板方法中有begin,commit等方法,事务管理器的子类分别实现自己的begin,commit,rollback等方法。

7、什么是aop

就是运行时,动态的将代码切入到类的指定方法指定位置上的编程思想。可以减少系统重复代码,降低耦合。Aop作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开。Aop的通知指的是拦截到目标方法后,要执行的代码,通知分为前置,后置,异常,环绕等。AOP代理分为静态代理:AspectJ和动态代理Spring AOP

aop的简单实现:https://blog.csdn.net/qq_37774171/article/details/86528612?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86528612-blog-50753592.pc_relevant_aa2&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86528612-blog-50753592.pc_relevant_aa2&utm_relevant_index=1

 此aop的切入点是个注解,被此注解标注的方法都会被aop增强。aop五种类型的通知注解:

@Before:前置通知,在方法执行之前执行

 @After:后置通知,在方法执行之后执行。在目标方法执行后(无论是否发生异常),执行的通知

 @AfterRunning:返回通知,在方法返回结果后执行,可以访问到方法的返回值的

 @AfterThrowing:异常通知,在方法抛出异常之后执行,可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码

 @Around:环绕通知,围绕着方法执行

8、jdk动态代理

jdk动态代理和CGLIB动态代理。动态代理是在内存中生成一个代理对象,这个代理对象包含了目标对象的全部方法,并在特定的切点做了增强处理,并回调原来的方法。增强处理包括方法执行前的权限检测,日志打印等

jdk动态代理:通过反射来接收被代理的类,创建一个代理类,客户端通过调用代理类来调用目标方法。调用目标类方法的过程中可以添加前置通知和后置通知等效果。核心类InnovationHandler接口, Proxy类。Proxy类:类的静态方法用来生成动态代理的实例。InnovationHandler接口有一个invoke方法,用来处理在动态代理类对象的方法调用,通常在该方法中实现对委托类的代理访问每次生成动态代理对象时都要指定一个对应的调用处理器。jdk动态代理demo:

public class MyAspect {
public void before() {
System.out.println("before");
}
public void after() {
System.out.println("after");
}
}
public interface UserService {
void addUser();
void updateUser();
}

public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("addUser");
}

@Override
public void updateUser() {
System.out.println("updateUser");
}
}

public class MyBeanFactory {

public static UserService createUserService() {
//目标类
UserService userService = new UserServiceImpl();
//切面类
MyAspect myAspect = new MyAspect();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
myAspect.before(); // 前执行
method.invoke(userService, args); //执行目标类方法
myAspect.after(); // 后执行
return o;
}
};
UserService proxyService = (UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(), invocationHandler);
return proxyService;
}

public static void main(String[] args) {
UserService userService = MyBeanFactory.createUserService();
userService.addUser();
userService.updateUser();
}
}

执行结果:

before
addUser
after
before
updateUser
after

 

Proxy.newProxyInstance()传入的参数:

1)loader,类加载器,动态代理类运行时创建

2)代理类要实现的接口

3)InvocationHandler:处理类,接口,一般采用匿名内部类,要实现invoke方法,代理类的每一个方法执行时,都会调用一次invoke。Invoke方法需要传入三个参数:Object proxy:代理对象,Method method利用反射调用目标类方法,args:方法实际参数

 jdk动态代理的目标类为什么必须要实现一个接口?https://www.51cto.com/article/702280.html

代理模式本来就需要代理类和被代理类同源,就是要么继承同一个类,要么实现同一个接口,而生成的代理对象Proxy0已经继承了Proxy类,由于java不能多继承,不能再继承其他的类,所以只能实现接口。

 如果目标类没有实现接口,且为final修饰,则不能进行spring aop编程。

 9、cglib动态代理

 CGLIB动态代理:原类似于jdk动态代理,jdk代理只能代理实现了接口的类。CGLIB针对类来实现代理,他的原是对指定的目标生成一个子类,并且覆盖其中方法实现增强,因为采用的是继承,所以不能对final修饰的进行代理,只是它在运行期间生的代理对象是针对目标类扩展的子类。cglib动态代理生成代理类的方式:

public static UserService createUserServiceCglib() {
//目标类
UserService userService = new UserServiceImpl();
//切面类
MyAspect myAspect = new MyAspect();
// 代理类,采用cglib,底层创建目标类的子类
Enhancer enhancer = new Enhancer();
//确定父类
enhancer.setSuperclass(userService.getClass());
/**
* MethodInterceptor接口等效jdk动态代理的InvocationHandler接口
* intercept等效jdk动态代理的invoke
*/
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
myAspect.before(); //前执行
Object obj = method.invoke(userService, objects); //执行目标类方法
methodProxy.invokeSuper(userService, objects); //执行代理类的父类
myAspect.after();//后执行
return obj;
}
};
// 设置回调函数
enhancer.setCallback(methodInterceptor);
UserServiceImpl proxyService = (UserServiceImpl) enhancer.create();
return proxyService;
}

jdk动态代理和cglib代理性能比较:jdk动态代理通过反射调用较慢,cglib代理是jdk代理速度的10倍,spring中的aop,如果目标类实现了接口,默认用jdk动态代理,如果目标类没有实现接口,就使用cglib动态代理

 10、spring事务:

spring事务分为声明式事务和编程式事务,声明式事务用aop实现的,事务会对目标类的方法前后进行拦截,包括获取线程绑定的资源,开启事务,提交回滚事务,异常处理等

spring事务失效的情况:

1)数据库引擎不支持事务

 这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。

2)没有被spring管理

如下面例子所示:

// @Service
public class OrderServiceImpl implements OrderService {

    @Transactional
    public void updateOrder(Order order) {
        // update order
    }

}

如果此时把 @Service 注解注释掉,这个类就不会被加载成一个 Bean,那这个类就不会被 Spring 管理了,事务自然就失效了。

 3)方法不是public,或者方法用final修饰

 @Transactional 只能用于 public 的方法上,否则事务不会失效,因为事务底层用到了aop动态代理,源码里获取对象方法时只获取到了public方法,即调用了clazz.getMethods()。

如果要用在非 public 方法上,可以开启 AspectJ 代理模式。如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法,而无法添加事务功能。因为事务底层使用了aop,aop创建了代理对象,如果方法是final的则代理类无法重写该方法

4)调用问题

 来看两个示例:

@Service
public class OrderServiceImpl implements OrderService {

    public void update(Order order) {
        updateOrder(order);
    }

    @Transactional
    public void updateOrder(Order order) {
        // update order
    }

}

 update方法上面没有加 @Transactional 注解,调用有 @Transactional 注解的 updateOrder 方法,updateOrder 方法上的事务管用吗?

再来看下面这个例子:

@Service
public class OrderServiceImpl implements OrderService {

    @Transactional
    public void update(Order order) {
        updateOrder(order);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateOrder(Order order) {
        // update order
    }

}

 这次在 update 方法上加了 @Transactional,updateOrder 加了 REQUIRES_NEW 新开启一个事务,那么新开的事务管用么?

 这两个例子的答案是:不管用!

 事务底层机制使用了aop,即jdk动态代理,最终方法的执行是通过代理对象执行的。 这个例子中方法之间发生了自身调用,相当于直接调用了this对象的方法,而没有经过代理对象的处理。如果是cglib动态代理,不涉及代理类,会生成目标类的子类,例子中的自身调用是有事务效果的。

5)数据源没有配置事务管理器

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

 如上面所示,当前数据源若没有配置事务管理器,那也是白搭!

6)事务不回滚的原因1:事务传播特性配置有误

其实,我们在使用@Transactional注解时,是可以指定propagation参数的,扩展其配置不支持事务

@Service 
public class OrderServiceImpl implements OrderService{ 
 
    @Transactional
    public void update(Order order) {
        updateOrder(order);
    }
 
  @Transactional(propagation = Propagation.NOT_SUPPORTED)
  public void updateOrder(Order order) {
        // update order
   }
}

我们可以看到add方法的事务传播特性定义成了Propagation.NOT_SUPPORTED,这种类型的传播特性不支持事务,如果有事务则会抛异常。

7)事务不回滚的原因2:异常吞掉了

这个也是出现比较多的场景:*把异常吃了,然后又不抛出来,事务也不会回滚! *比如:

@Service

public class OrderServiceImpl implements OrderService {
 
    @Transactional
    public void updateOrder(Order order) {
        try {
            // update order
        } catch {
        }
    }
}
8)手动抛了别的异常

即使开发者没有手动捕获异常,但如果抛的异常不正确,spring事务也不会回滚。

@Service

public class OrderServiceImpl implements OrderService {
    @Transactional
    public void updateOrder(Order order) {
        try {
            // update order
        } catch {
            throw new Exception("更新错误");
        }
    }
}

这样事务也是不生效的,因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:@Transactional(rollbackFor = Exception.class), 这个配置仅限于 Throwable 异常类及其子类。

11、spring事务传播特性

1)Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

2)Propagation.REQUIRES_NEW:表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。

3)Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

 11Spring单例bean与设计模式单例的区别:

区别在于它们关联的环境不一样,后者是指在一个jvm进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)仅有一个实例所以Spring单例是与容器密切相关的,所以在一个jvm进程中,如果有多个Spring容器,即使是单例bean,也一定会创建多个实例

 12、@Configuration注解

类似ClassPathXmlApplicationContext的xml文件

ClassPathXmlApplicationContext和xml一起使用的方式:https://blog.csdn.net/gaopeng0071/article/details/46971405

@ComponentScan此注解一般和@Configuration注解一起使用,指定Spring扫描注解的package。如果没有指定包,那么默认会扫描此配置类所在的package。

@Configuration一般和@Bean注解一起用,表示把bean注入到容器中

13、@ConfigurationProperties注解可以获取application.yml配置的参数,比如yml配置:

mysql-datasource:
configs:
liveArenaChickenDB:
type: sharding
cluster-name: mysql_proxy_live_chicken_pk
pool-config:
maxConn: 100
minConn: 10
initConn: 10
checkoutTimeoutInMill: 5000
liveHappyBattleDB:
type: master-slave
cluster-name: mysql_proxy_live_happy_battle
database: liveHappyBattle
pool-config:
checkoutTimeoutInMill: 5000

代码获取配置:

@ConfigurationProperties(prefix = "mysql-datasource")
@Data
public class ArenaChickenDataSource {
private Map<String, MysqlProperty> configs;
@Data
public static class MysqlProperty {
private String type;
private String clusterName;
private String database;
private PoolConfig poolConfig;
private Map<String, String> jdbcParams;
private Properties properties;
}
@Bean
public NamedParameterJdbcTemplate liveArenaChickenDB() {
return new NamedParameterJdbcTemplate(getDataSource(configs.get("liveArenaChickenDB")));
}
@Bean
public NamedParameterJdbcTemplate liveHappyBattleDB() {
return new NamedParameterJdbcTemplate(getDataSource(configs.get("liveHappyBattleDB")));
}
private DataSource getDataSource(MysqlProperty mysqlProperties) {
log.info("dataSource, type:{}, clusterName:{}, database:{}",
mysqlProperties.getType(), mysqlProperties.getClusterName(), mysqlProperties.getDatabase());
DataSource dataSource = null;
if ("master-slave".equalsIgnoreCase(mysqlProperties.getType())) {
dataSource = new MasterSlaveDataSourceWrapper(mysqlProperties.getClusterName(),
mysqlProperties.getPoolConfig(),
mysqlProperties.getJdbcParams(),
mysqlProperties.getProperties(),
mysqlProperties.getDatabase());
} else if ("sharding".equalsIgnoreCase(mysqlProperties.getType())) {
dataSource = new ShardDataSourceWrapper(mysqlProperties.getClusterName(),
mysqlProperties.getPoolConfig(),
mysqlProperties.getJdbcParams(),
mysqlProperties.getProperties());
}
if (dataSource == null) {
throw new IllegalArgumentException("mysql-datasource 配置里的type 只能为 master-slave 或者 sharding");
}
return dataSource;
}
}
13、springboot:
SpringBoot是一个快速开发框架,快速的将一些常用的第三方依赖整合(原理:通过Maven子父工程的方式),简化XML配置,全部采用注解形式,内置Http服务器(Jetty和Tomcat),最终以java应用程序进行执行,它是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置,降低开发的难度
14、springboot starter作用
能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。比如引入了spring-boot-starter-web,我们发现,陆陆续续的下载了很多jar包。web的Starter给我们提供了webmvc、web、tomcat和json的能力,那么,也就能够解释为什么我们自己没有去配置tomcat,项目却可以自己跑起来的原因了

15、springboot的自动装配
自动配置简单来说呢,就是将第三方的组件自动装载到IOC容器里面,不需要开发人员再去编写相关的配置,在SpringBoot应用里面只需要加上@SpringBootApplication注解就可以实现自动配置,SpringBootApplication是一个复合注解,包括:
@SpringBootConfiguration,用于声明配置类,一般和@Bean一起使用,表示把bean注入到容器中
@EnableAutoConfiguration,启用Spring boot的自动装配机制
@ComponentScan,启动组件扫描

16、springboot约定大于配置的理解

约定大于配置核心思想是减少软件开发人员对于配置项的维护,可以更专注于业务逻辑上。传统的spring开发需要做很多配置项比如web.xml,servlet.xml,应用部署到web容器,第三方组件集成到spring ioc容器的配置项维护。springboot中不需要再做这些繁琐的配置,springboot帮我们完成了这些操作,这就是约定大于配置。

17、spring bean是不是线程安全的?

a)如果是prototype即原型Bean,每次请求容器都创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。

@RestController
@Scope(value = "prototype") // 加上@Scope注解,他有2个取值:单例-singleton 多实例-prototype
public class TestController {

private int var = 0;

@GetMapping(value = "/test_var")
public String test() {
System.out.println("普通变量var:" + (++var));
return "普通变量var:" + var ;
}
}

这样一来,每个请求都单独创建一个Controller bean,所以各个请求之间是线程安全的,三次请求结果:

普通变量var:1
普通变量var:1
普通变量var:1

如果prototype类型的controller有静态变量,也是线程不安全的,因为静态变量被所有实例共享

b)如果是单例Bean,所有线程都共享一个单例实例Bean,非线程安全

@RestController
public class TestController {

private int var = 0;

@GetMapping(value = "/test_var")
public String test() {
System.out.println("普通变量var:" + (++var));
return "普通变量var:" + var ;
}
}

在postman里面发三次请求,结果如下:

普通变量var:1
普通变量var:2
普通变量var:3
 

18、spring有几种方式把bean注入到ioc容器

1)xml方式,在xml中声明bean的定义
2)使用@ComponentScan注解来扫描@Controller,@Service,@Repository等注解的类
3)使用@Configuration注解声明配置类,使用@Bean注解实现Bean的定义,这个是xml方式的演变

19、spring bean作用域:

1)singleton即单例,意味着在整个spring容器中只会存在一个bean实例
2)prototype即原型,意味着每次从IOC容器去获取指定bean的时候,都会返回一个新的实例对象
3)request,针对每一次http请求都会创建一个新的bean
4)session,以session会话为维度,同一个session共享同一个bean实例,不同的session产生不同的bean实例
5)globalSession,全局session维度共享一个bean实例
如果不指定Bean的作用域,Spring默认使用singleton作用域

posted @ 2023-02-08 11:00  MarkLeeBYR  阅读(31)  评论(0)    收藏  举报