本文试图从原理上讲解Spring IoC容器的作用域机制,建议对着源码阅读,事半功倍。

0 引入问题

当我们谈到Spring作用域的时候,自然而然会想到如下作用域(来自spring-core官方文档):

作用域 描述
singleton (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
request Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

从功能上看,这些作用域分别定义了调用org.springframework.beans.factory.BeanFactory#getBean()方法时,容器根据bean definition实例化bean object的规则。

从底层实现上看,这些作用域可以分成两类:

  1. 内置作用域:singletonprototype
  2. 自定义作用域:requestsessionapplicationwebsocket以及我们自定义的作用域。

所有Spring IoC容器中都具备singletonprototype作用域功能,而只有实现Web功能的容器(如org.springframework.web.context.support.GenericWebApplicationContext接口)中才具备requestsession等作用域功能。这是因为它们底层的实现机制不同。

spring-core官方文档中说了这么一段话:

我个人这么理解作用域机制的扩展性:

  1. 内置的singletonprototype作用域——不可扩展。
  2. 可以复写requestsession等预定义作用域的规则——可扩展。
  3. 可以自定义作用域——可扩展。

以上简要概括了Spring IoC容器作用域的基本概念,希望能够引起大家思考以下几个问题(本文后续部分会一一探讨):

  1. 什么是作用域?如何使用作用域?
  2. 作用域的底层原理?
  3. 内置作用域和自定义作用域的区别?
  4. 如何自定义作用域?

1 什么是作用域?如何使用作用域?

1.1 什么是作用域?

作用域是个很宽泛的概念,本文讨论的特指是Spring IoC容器中Bean对象的作用域,简单可以理解成:bean对象的存活范围。

为了便于深入理解,我们先要大概了解一下Spring IoC容器的工作原理。Spring IoC容器的使用流程大概可以分为以下3个步骤:

flowchart LR
配置文件 --> 创建容器 --> 获取bean
  1. 配置Bean

    @Configuration
    public class AppConfiguration {
    @Bean
    public A a() {
    return new A();
    }
    } class A { }
  2. 创建Spring IoC容器,并读取配置信息:

    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class);
  3. 从容器中获取bean,并使用:

    A a = context.getBean("a", A.class);
    System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@16267862
    a = context.getBean("a", A.class);
    System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@16267862

Bean作用域本质上指的是多次调用context.getBean()方法获取到的是否是同一个bean对象。

上面例子中,默认指定作用域为singleton,所以两次调用context.getBean()方法获取到同一个对象。

如果指定作用域为prototype

@Bean
@Scope("prototype")
public A a() {
return new A();
}

此时,两次调用context.getBean()方法获取到就是两个对象了:

A a = context.getBean("a", A.class);
System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@49070868
a = context.getBean("a", A.class);
System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@6385cb26

1.2 如何使用作用域?

作用域的使用比较简单,只需要在配置Bean时使用指定作用域即可。我们使用作用域的重点其实在于不同作用域下context.getBean()的规则。

1.2.1 singleton

singleton作用域下,多次调用context.getBean()方法获取到同一个对象。

  • 配置:
@Configuration
public class AppConfiguration {
@Bean
public A a() {
return new A();
}
} class A {}
  • 使用:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class);
A a = context.getBean("a", A.class);
System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@16267862
a = context.getBean("a", A.class);
System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@16267862

1.2.2 prototype

prototype作用域下,每次调用context.getBean()方法获取到新对象。

  • 配置:
@Configuration
public class AppConfiguration {
@Bean
@Scope("prototype")
public A a() {
return new A();
}
} class A {}
  • 使用:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class);
A a = context.getBean("a", A.class);
System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@49070868
a = context.getBean("a", A.class);
System.out.println(a); // com.xianhuii.spring.beanscopes.demo01.A@6385cb26

2 作用域的底层原理?

Bean作用域本质上指的是多次调用context.getBean()方法获取到的是否是同一个bean对象。

所以,作用域底层执行原理在context.getBean()方法中,其中与作用域有关的执行流程如下:

flowchart TD
A[获取BeanDefinition] --> B{scope?};
B -->|singleton| C[singleton创建规则];
B -->|prototype| D[prototype创建规则];
B -->|自定义作用域| E[自定义创建规则];
  1. BeanFactory中获取已加载的BeanDefinition,判断该Bean的作用域。
  2. 如果是singleton作用域,则执行单例创建规则。
  3. 如果是prototype作用域,则执行原型创建规则。
  4. 如果是自定义作用域,则执行自定义创建规则。

相关核心源码如下(org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean()):

// 获取BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 1、如果作用域是singleton,执行对应创建规则:创建bean,并放到容器中
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 2、如果作用域是prototype,执行对应创建规则:创建bean,但不会放到容器中
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 3、如果是自定义作用域,执行对应创建规则:自定义规则
else {
String scopeName = mbd.getScope();
Scope scope = this.scopes.get(scopeName);
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}

2.1 singleton作用域

singleton作用域bean对象的创建过程分为三个步骤:

  1. 判断是否为singleton作用域。
  2. 根据singleton规则创建bean对象。
  3. bean对象进行后处理。

1、判断

mbd.isSingleton()方法(org.springframework.beans.factory.support.AbstractBeanDefinition#isSingleton)的源码如下:

public boolean isSingleton() {
return SCOPE_SINGLETON.equals(this.scope) || SCOPE_DEFAULT.equals(this.scope);
}

其中两个静态变量分别为:

String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;	// "singleton"
public static final String SCOPE_DEFAULT = "";

所以,我们在声明Bean时,以下情况会声明为singleton作用域:

  1. 默认情况(即不显示指定作用域),会默认声明为SCOPE_DEFAULT作用域,而SCOPE_DEFAULT实际上就是singleton作用域。

    @Bean
    public A a() {
    return new A();
    }
  2. 显示指定为singleton作用域,通过@Scope("singleton")等方式。

    @Bean
    @Scope("singleton")
    public A a() {
    return new A();
    }
  3. 显示指定为默认作用域,通过@Scope等方式。

    @Bean
    @Scope
    public A a() {
    return new A();
    }

2、创建单例bean

创建单例bean的源码如下:

sharedInstance = getSingleton(beanName, () -> {
try {
// 创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 创建失败,删除缓存
destroySingleton(beanName);
throw ex;
}
});

其核心在于org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)方法,其中定义了大部分创建单例bean的规则(模板方法模式):

  1. singletonObjects对象(单例对象缓存)加锁:一次只能创建一个单例对象。
  2. singletonObjects中获取当前beanName的对象。
  3. 如果存在,说明已经创建,直接返回。
  4. 如果不存在,说明还没有创建,则进行创建对象:
    1. 预处理。
    2. 创建对象。
    3. 后处理。
    4. 添加到singletonObjects缓存。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 1、singletonObjects缓存加锁
synchronized (this.singletonObjects) {
// 2、从singletonObjects缓存中获取singletonObject
Object singletonObject = this.singletonObjects.get(beanName);
// 3、如果不存在,则创建新对象
if (singletonObject == null) {
// 3.1、预处理
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
// 3.2、创建对象
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
}
catch (BeanCreationException ex) {
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 3.3、后处理
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 3.4、添加到singletonObjects缓存
addSingleton(beanName, singletonObject);
}
}
// 4、如果存在,直接返回
return singletonObject;
}
}

其中,预处理和后处理都是单例对象创建过程中的回调,可以通过重写自定义回调规则。默认情况下,预处理和后处理会分别标记/清除单例对象“创建中”的标记。

addSingleton(beanName, singletonObject)方法会将该对象添加到singletonObjects单例对象缓存和registeredSingletons已注册单例对象缓存中,并将该对象从singletonFactories单例工厂缓存和earlySingletonObjects早期单例对象缓存中移除:

protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

最重要的singletonFactory.getObject()方法是外部传入的,即调用该方法实际上会执行外部传入的匿名对象中定义的方法:

  1. 调用createBean(beanName, mbd, args)会使用反射机制创建bean对象。
  2. 如果创建失败,则调用destroySingleton(beanName)方法删除相关缓存信息。
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}

3、后处理

org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance方法会对上述根据BeanDefinition创建处理bean进行后处理,该方法其实就是Spring AOP功能的入口。其内部会进行如下判断:

  1. 容器内部使用。
  2. 是否为普通bean:直接返回。
  3. 是否为org.springframework.beans.factory.FactoryBean实现类:Spring AOP核心类。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // 1、pring容器内部bean,不必太过关注
if (BeanFactoryUtils.isFactoryDereference(name)) {} // 2、普通bean,直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
} // 3、FactoryBean对象,通过AOP功能获取其真正代理的对象
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
} else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

2.2 prototype作用域

prototype作用域bean对象的创建过程分为三个步骤:

  1. 判断是否为prototype作用域。
  2. 根据prototype规则创建bean对象。
  3. prototype对象进行后处理。

1、判断

mbd.isPrototype()方法(org.springframework.beans.factory.support.AbstractBeanDefinition#isPrototype)的源码如下:

public boolean isPrototype() {
return SCOPE_PROTOTYPE.equals(this.scope);
}

其中静态变量为:

String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;	// "prototype"

所以,我们在声明Bean时,可以通过@Scope("prototype")等方式显示指定为prototype作用域:

@Bean
@Scope("prototype")
public A a() {
return new A();
}

2、创建原型bean

有了以上经验,我们就能很容易理解创建原型bean的源码:

Object prototypeInstance = null;
try {
// 1、预处理,默认标记为“创建中”状态
beforePrototypeCreation(beanName);
// 2、通过反射机制创建对象
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 3、后处理,默认移除“创建中”标记
afterPrototypeCreation(beanName);
}

3、后处理

该后处理过程与singleton作用域完全相同。

2.3 自定义作用域

如果BeanDefinition既不是singleton,也不是prototype,那么就会执行自定义作用域的创建规则:

  1. 获取BeanDefinitionscope属性值。
  2. BeanFactory的作用域缓存scopes中获取对应的作用域。
  3. 调用scope.get()方法,执行自定义创建规则。
  4. 后处理:Spring AOP功能入口,与singletonprototype相同。
// 1、获取BeanDefinition的scope属性值
String scopeName = mbd.getScope();
// 2、从BeanFactory的作用域缓存scopes中获取对应的作用域
Scope scope = this.scopes.get(scopeName);
try {
// 3、执行自定义创建规则
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
// 4、后处理
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}

从以上源码中我们可以得出自定义作用域的三个步骤:

  1. 创建作用域实现类:实现org.springframework.beans.factory.config.Scope接口,实现其get()方法。

    classDiagram
    class Scope
    Scope : +get(String name, ObjectFactory<?> objectFactory)
  2. 将作用域实现类注册到BeanFactoryscopes缓存中:key为作用域名,value为自定义作用域对象(org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope)。

  3. 配置Bean时,指定对应的作用域名。

3 内置作用域和自定义作用域的区别?

通过上述的讲解,想必大家对内置作用域(singletonprototype)和自定义作用域的区别有了本质上的理解。

内置作用域的作用域名和bean创建规则已经写死到Spring IoC容器中。

自定义作用域通过自定义的作用域名从BeanFactoryscopes缓存中找到自定义作用域实现类,根据其中实现的get()方法创建bean。同时,自定义作用域的bean对象存放于自定义的缓存中。

4 自定义作用域案例:request

接下来,我们以request作用域为例,展示如何自定义作用域。

4.1 RequestScope实现类

该实现类全限定类名为org.springframework.web.context.request.RequestScope。类图如下:

classDiagram
class Scope
Scope : +get(String name, ObjectFactory<?> objectFactory)
Scope <|-- AbstractRequestAttributesScope
AbstractRequestAttributesScope <|-- RequestScope

其中,最核心的的部分在于org.springframework.web.context.request.AbstractRequestAttributesScope#get

  1. 获取当前请求的RequestAttributes对象。
  2. 从缓存中获取bean
  3. 如果缓存中不存在,则需要重新创建:
    1. 使用objectFactory匿名对象创建bean
    2. bean放到缓存中。
    3. 重新从缓存中获取。
  4. 如果缓存中存在,直接返回。
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 1、获取当前请求的RequestAttributes缓存对象。
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
// 2、从缓存中获取bean
Object scopedObject = attributes.getAttribute(name, getScope());
// 3、如果缓存中不存在,则需要重新创建
if (scopedObject == null) {
// 3.1、使用objectFactory匿名对象创建bean
scopedObject = objectFactory.getObject();
// 3.2、将bean存放到缓存中
attributes.setAttribute(name, scopedObject, getScope());
// 3.3、重新从缓存中获取
// Retrieve object again, registering it for implicit session attribute updates.
// As a bonus, we also allow for potential decoration at the getAttribute level.
Object retrievedObject = attributes.getAttribute(name, getScope());
if (retrievedObject != null) {
// Only proceed with retrieved object if still present (the expected case).
// If it disappeared concurrently, we return our locally created instance.
scopedObject = retrievedObject;
}
}
// 4、如果缓存中存在,直接返回
return scopedObject;
}

4.2 注册作用域

在实现Web功能的容器(如org.springframework.web.context.support.GenericWebApplicationContext接口)中,会自动将request等自定义作用域注册到BeanFactoryscopes缓存中:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
if (this.servletContext != null) {
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
}

在这里会调用封装好的WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);方法进行注册:

public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
@Nullable ServletContext sc) { // 1、注册request作用域:key为request,value为RequestScope实现类
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
// 2、注册session作用域:key为session,value为SessionScope实现类
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
if (sc != null) {
// 3、注册application作用域:key为application,value为ServletContextScope实现类
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
sc.setAttribute(ServletContextScope.class.getName(), appScope);
} beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}

4.3 配置Bean

在定义Bean时,通过指定作用域为request即可:

@Bean
@Scope("request")
public A a() {
return new A();
}

为了方便,Spring还实现了@RequestScope注解,使用方式如下:

@Bean
@RequestScope
public A a() {
return new A();
}

@RequestScope本质上和@Scope("request")没有任何区别(不过我们在自定义作用域时可以采用类似的方式来炫技):

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_REQUEST) // 相当于@Scope("request")
public @interface RequestScope { /**
* Alias for {@link Scope#proxyMode}.
* <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
*/
@AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS; }

5 自定义作用域实战

在文章的最后,我们通过实战来自定义作用域myScope,用来简单模拟singleton作用域:

  1. 第一次调用context.getBean()方法时创建新bean
  2. 之后每次调用context.getBean()方法都会获取同一个bean

5.1 MyScope实现类

该实现类核心在于get()方法,其他方法都使用默认实现,因此省略:

public class MyScope implements Scope {
// bean缓存
private static Map<String, Object> beanMap = new ConcurrentHashMap<>(); @Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 1、从缓存中获取bean
Object bean = beanMap.get(name);
// 2、如果缓存中不存在,则新建
if (bean != null) {
// 2.1创建bean实例
bean = objectFactory.getObject();
// 2.2、放到缓存中
beanMap.put(name, bean);
}
// 3、如果缓存中存在,则直接返回
return bean;
}
}

5.2 注册作用域

注册作用域的方法定义为org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope

@Configuration
public class AppConfiguration implements BeanFactoryAware {
private BeanFactory beanFactory; @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
} @PostConstruct
public void registerScope() {
if (beanFactory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
configurableBeanFactory.registerScope("myScope", new MyScope());
}
}
}

5.3 配置Bean

@Bean
@Scope("myScope")
public A a() {
return new A();
}

5.4 测试

@SpringBootApplication
public class Application implements ApplicationContextAware { @Bean
public ApplicationRunner runner() {
return new ApplicationRunner() {
@Override
public void run(ApplicationArguments args) throws Exception {
A a = applicationContext.getBean("a", A.class);
System.out.println(a);
MyScope.getBeanMap().forEach((key, value) -> {
System.out.println("key: " + key + ", value: " + value);
});
a = applicationContext.getBean("a", A.class);
System.out.println(a);
MyScope.getBeanMap().forEach((key, value) -> {
System.out.println("key: " + key + ", value: " + value);
});
}
};
} private ApplicationContext applicationContext; public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

输出结果为:

com.xianhuii.springboot.demo.A@757194dc
key: a, value: com.xianhuii.springboot.demo.A@757194dc
com.xianhuii.springboot.demo.A@757194dc
key: a, value: com.xianhuii.springboot.demo.A@757194dc

[spring-core]作用域的更多相关文章

  1. 【Spring】IoC容器 - Spring Bean作用域Scope(含SpringCloud中的RefreshScope )

    前言 上一章学习了[依赖来源],本章主要讨论SpringBean的作用域,我们这里讨论的Bean的作用域,很大程度都是默认只讨论依赖来源为[Spring BeanDefinition]的作用域,因为在 ...

  2. 【Spring开发】—— Spring Core

    原文:[Spring开发]-- Spring Core 前言 最近由于一些工作的需要,还有自己知识的匮乏再次翻开spring.正好整理了一下相关的知识,弥补了之前对spring的一些错误认知.这一次学 ...

  3. vs2012+Spring.Core.dll

    Ⅰ.Spring的点点滴滴--序章   spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架 .net篇(环境为vs2012+Spring.Core.dll) 新建一个控制台 u ...

  4. spring core 与 context理解

    Spring core是核心层,拥有这BeanFactory这个强大的工厂,是所有bean的管理器: 而spring context是上下文运行环境,基于spring core之上的一个架构, 它之上 ...

  5. spring scope 作用域

    转自:http://www.cnblogs.com/qq78292959/p/3716827.html 今天研究了一下scope的作用域.默认是单例模式,即scope="singleton& ...

  6. 多个IoC容器适配器设计及性能测试(Castle.Windsor Autofac Spring.Core)

    [转]多个IoC容器适配器设计及性能测试和容器选择 1. 采用的IoC容器和版本 Autofac.2.6.3.862 Castle.Windsor.3.1.0 Spring.Core.2.0.0 2. ...

  7. Spring bean作用域

    全当知识要点记录了,大家随意踩踩. spring的作用域有以下几种singleton作用域prototype作用域request作用域session作用域global-session作用域 1. si ...

  8. Spring core resourc层结构体系及JDK与Spring对classpath中资源的获取方式及结果对比

    1. Spring core resourc层结构体系 1.1. Resource相关结构体系 1.2. ResourceLoader相关体系 2. JDK与Spring对classpath中资源的获 ...

  9. Spring 中 ApplicationContext 和 BeanFactory 的区别,以及 Spring bean 作用域

    //从ApplicationContext 中取 bean ApplicationContext ac = new ClassPathXmlApplicationContext ( "com ...

  10. spring core:@AliasFor的派生性

    spring对Annotation的派生性应用可谓炉火纯青,在spring core:@Component的派生性讲过支持层次上派生性,而属性上派生的需求则借助了@AliasFor,它是从spring ...

随机推荐

  1. Windows用cmd编译运行C程序

    在Windows环境下用命令行编译运行程序 浙江大学-C语言程序设计进阶 配置gcc 准备一个Dev-cpp 找到gcc.exe所在目录 Dev-Cpp\MinGW64\bin 地址栏右键将地址复制为 ...

  2. pycharm环境下配置scrap爬虫环境

    [写在开头] 参考文章后面给出了备注信息,是在解决这个问题的时候,查找的比较有亮点的参考文章,如果本文章写的不太清楚的,可以去原文章进行查看.下面列举的四个文章有参考的成分也有验证的成分,解决办法重点 ...

  3. 【数学】快速傅里叶变换(FFT)

    快速傅里叶变换(FFT) FFT 是之前学的,现在过了比较久的时间,终于打算在回顾的时候系统地整理一篇笔记,有写错的部分请指出来啊 qwq. 卷积 卷积.旋积或褶积(英语:Convolution)是通 ...

  4. Wireshark 过滤器的使用

    符号 例子 = = tcp.port = = 80 过滤出来TCP包含80端口的数据包 != ip.src != 127.0.0.1 ip的原地址不是127.0.0.1过滤出来 > lp.len ...

  5. Elasticsearch 中为什么选择倒排索引而不选择 B 树索引

    目录 前言 为什么全文索引不使用 B+ 树进行存储 全文检索 正排索引 倒排索引 倒排索引如何存储数据 FOR 压缩 RBM 压缩 倒排索引如何存储 字典树(Tria Tree) FST FSM 构建 ...

  6. spring security实现简单的url权限拦截

    在一个系统中,权限的拦截是很常见的事情,通常情况下我们都是基于url进行拦截.那么在spring security中应该怎么配置呢. 大致步骤如下: 1.用户登录成功后我们需要拿到用户所拥有的权限,并 ...

  7. 2021.8.14考试总结[NOIP模拟39]

    T1 打地鼠 全场就俩人没切,还有一个是忘关$freopen$了. $code:$ 1 #include<bits/stdc++.h> 2 #define rin register sig ...

  8. AtCoder Beginner Contest 182 F

    F - Valid payments 简化题意:有\(n\)种面值的货币,保证\(a[1]=1,且a[i+1]是a[i]的倍数\). 有一个价格为\(x\)元的商品,付款\(y\)元,找零\(y-x\ ...

  9. 【python】使用python十分钟创建个人聊天机器人教程

    以青云客和图灵机器人接口示范python创建个人聊天机器人教程 一.以青云客聊天机器人为例示范get请求 官方网址:http://api.qingyunke.com/ 1.接入指引 请求地址 http ...

  10. springboot注解之容器功能

    添加组件 @Configuration.@Bean //以swagger为例 @Configuration(proxyBeanMethods = false) @EnableSwagger2 //使用 ...