本文试图从原理上讲解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. Pytorch 实现简单线性回归

    Pytorch 实现简单线性回归 问题描述: 使用 pytorch 实现一个简单的线性回归. 受教育年薪与收入数据集 单变量线性回归 单变量线性回归算法(比如,$x$ 代表学历,$f(x)$ 代表收入 ...

  2. Zookeeper+Dubbo环境搭建与Demo测试

     环境准备: 1. zookeeper-3.4.14     (下载地址:http://archive.apache.org/dist/zookeeper/) 2. dubbo-0.2.0 (下载地址 ...

  3. 经典论文系列 | 缩小Anchor-based和Anchor-free检测之间差距的方法:自适应训练样本选择

    ​  前言  本文介绍一篇CVPR2020的论文,它在paperswithcode上获得了16887星,谷歌学术上有261的引用次数. 论文主要介绍了目标检测现有的研究进展.anchor-based和 ...

  4. 使用包图 (UML Package Diagram) 构建模型架构

    包图用于以包包含层次结构的形式显示模型的组织方式.包图还可以显示包包含的模型元素以及包与其包含的模型元素之间的依赖关系. 在项目开发中,模型元素可能会很快达到大量数量,因此需要以某种方式构建它们,即使 ...

  5. Java:AQS 小记-2(ReentrantLock)

    Java:AQS 小记-2(ReentrantLock) 整体结构 ReentrantLock 类图 AbstractOwnableSynchronizer 类 public abstract cla ...

  6. BUAA SE 个人项目作业

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人项目作业 我在这个课程的目标是 通过个人项目实践熟悉个人开发流程 一.在文章开头给出教学班级和 ...

  7. Spring源码解读(二):Spring AOP

    一.AOP介绍 面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP).OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面.方面实现了诸如跨越多种类型和对象的事务 ...

  8. web性能检测工具lighthouse

    About Automated auditing, performance metrics, and best practices for the web. Lighthouse 可以自动检查Web页 ...

  9. mybatis竟然报"Invalid value for getInt()"

    目录 背景 场景 初探 再探 结局 背景 使用mybatis遇到一个非常奇葩的问题,错误如下: Cause: org.apache.ibatis.executor.result.ResultMapEx ...

  10. Android 服务名称规则invalid service name 限制16字符以内

    今天调试网络服务的时候为了区分,修改了原有服务名称,同时新增了两个服务. 系统运行的时候报错找不到对应的服务 init: no such service 'wpa_supplicant_common' ...