Spring Core IOC 随手笔记

The most flexible variant is GenericApplicationContext in combination with reader delegates — for example, with XmlBeanDefinitionReader for XML files, as the following example shows:
最灵活的变体是GenericApplicationContext与读取器委托结合使用,例如,与XML文件的XmlBeanDefinitionReader结合使用,如以下示例所示:

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

The bean definition

Property Explained in…​
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks

Bean 注册 补充

In addition to bean definitions that contain information on how to create a specific bean, the ApplicationContext implementations also permit the registration of existing objects that are created outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory through the getBeanFactory() method, which returns the BeanFactory DefaultListableBeanFactory implementation. DefaultListableBeanFactory supports this registration through the registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications work solely with beans defined through regular bean definition metadata.

除了包含有关如何创建特定bean的信息的bean定义之外,ApplicationContext实现还允许由用户创建的Spring 托管类。这是通过通过getBeanFactory()方法访问ApplicationContext的BeanFactory来完成的,该方法返回BeanFactory DefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(…)和registerBeanDefinition(…)方法支持此注册。但是,典型的应用程序只能与通过常规bean定义元数据定义的bean一起使用。

Spring 标签

P-NameSpace

简化内部属性XML的配置 since Spring 3.1

xml 简化配置 ,达到相同效果

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="john-classic" class="com.example.Person">
        <property name="name" value="John Doe"/>
        <property name="spouse" ref="jane"/>
    </bean>

    <bean name="john-modern"
        class="com.example.Person"
        p:name="John Doe"
        p:spouse-ref="jane"/>

    <bean name="jane" class="com.example.Person">
        <property name="name" value="Jane Doe"/>
    </bean>
</beans>

C-NameSpace

简化构造函数XML属性的配置 since Spring 3.1

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="beanTwo" class="x.y.ThingTwo"/>
    <bean id="beanThree" class="x.y.ThingThree"/>

    <!-- traditional declaration with optional argument names -->
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg name="thingTwo" ref="beanTwo"/>
        <constructor-arg name="thingThree" ref="beanThree"/>
        <constructor-arg name="email" value="[email protected]"/>
    </bean>

    <!-- c-namespace declaration with argument names -->
    <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
        c:thingThree-ref="beanThree" c:email="[email protected]"/>

</beans>

depends-on

如果一个bean是另一个bean的依赖项,则通常意味着将一个bean设置为另一个bean的属性。通常,您可以使用基于XML的配置元数据中的元素来完成此操作。但是,有时bean之间的依赖性不太直接。一个示例是何时需要触发类中的静态初始值设定项,例如用于数据库驱动程序注册。依赖属性可以显式地强制初始化一个或多个使用该元素的bean之前的bean。以下示例使用depends-on属性来表示对单个bean的依赖关系:

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao" p:manager-ref="manager"></bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

idref

The idref element is simply an error-proof way to pass the id (a string value - not a reference) of another bean in the container to a <constructor-arg/> or <property/> element. The following example shows how to use it:

Google翻译:

idref元素只是一种防错方法,可以将容器中另一个bean的id(字符串值-不是引用)传递给<constructor-arg />或<property />元素。以下示例显示了如何使用它:

<bean id="theTargetBean" class="..." />

<bean id="client" class="...">
    <property name="targetName" value="theTargetBean"/>
</bean>
替代:
<bean id="theClientBean" class="...">
    <property name="targetName">
        <idref bean="theTargetBean"/>
    </property>
</bean>

第一种形式优于第二种形式,因为使用idref标记可使容器在部署时验证所引用的命名bean实际存在。

在第二个变体中,不对传递给客户端bean的targetName属性的值执行验证。

拼写错误仅在实际实例化客户端bean时才发现(可能会导致致命的结果)。如果客户端bean是原型bean,则可能在部署容器很长时间之后才发现此错字和所产生的异常。

null

元素处理空值。以下清单显示了一个示例:

<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>

Spring bean 范围

Scope Description 中文
singleton (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. (默认值)将每个Spring IoC容器的单个bean定义范围限定为单个对象实例。
prototype Scopes a single bean definition to any number of object instances. 将单个bean定义的作用域限定为任意数量的对象实例。
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. 将单个bean定义的范围限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有一个在单个bean定义后面创建的bean实例。仅在可感知网络的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. 将单个bean定义的作用域限定为HTTP会话的生命周期。仅在可感知网络的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. 将单个bean定义的作用域限定为ServletContext的生命周期。仅在可感知网络的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. 将单个bean定义的作用域限定为WebSocket的生命周期。仅在可感知网络的Spring ApplicationContext上下文中有效。

prototype

与其他作用域相反,Spring不管理prototype Bean的完整生命周期。容器实例化,配置或组装原型对象,然后将其交给客户端,而没有该原型实例的进一步记录。因此,尽管在不考虑范围的情况下在所有对象上都调用了初始化生命周期回调方法,但对于原型而言,不会调用已配置的销毁生命周期回调。客户端代码必须清除prototype作用域内的对象并释放原型Bean拥有的昂贵资源。为了使Spring容器释放原型作用下的bean所拥有的资源,请尝试使用自定义bean后处理器,该处理器具有对需要清理的bean的引用。

但是,假设您希望单例作用域的bean在运行时重复获取原型作用域的bean的新实例。您不能将prototype作用域的bean依赖项注入到您的单例bean中,因为当Spring容器实例化单例bean并解析并注入其依赖项时,该注入仅发生一次。如果在运行时不止一次需要原型bean的新实例,请参见方法注入

The request, session, application, and websocket

仅当您使用可感知网络的Spring ApplicationContext实现(例如XmlWebApplicationContext)时request, session, application, and websocket 范围才可用。如果您将这些作用域与常规的Spring IoC容器(例如ClassPathXmlApplicationContext)一起使用,则会抛出一个IllegalStateException,抛出未知的bean作用域。

自定义Scope

  • 实现org.springframework.beans.factory.config.Scope 接口

  • org.springframework.beans.factory.config.ConfigurableBeanFactory#registerScope 注入

  • code

public class SimpleMapScope implements Scope, Serializable {

	private final Map<String, Object> map = new HashMap<>();

	private final List<Runnable> callbacks = new LinkedList<>();


	public SimpleMapScope() {
	}

	public final Map<String, Object> getMap() {
		return this.map;
	}


	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		synchronized (this.map) {
			Object scopedObject = this.map.get(name);
			if (scopedObject == null) {
				scopedObject = objectFactory.getObject();
				this.map.put(name, scopedObject);
			}
			return scopedObject;
		}
	}

	@Override
	public Object remove(String name) {
		synchronized (this.map) {
			return this.map.remove(name);
		}
	}

	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
		this.callbacks.add(callback);
	}

	@Override
	public Object resolveContextualObject(String key) {
		return null;
	}

	public void close() {
		for (Iterator<Runnable> it = this.callbacks.iterator(); it.hasNext();) {
			Runnable runnable = it.next();
			runnable.run();
		}
	}

	@Override
	public String getConversationId() {
		return null;
	}

}

-----
@Test
	public void testScopedOverride() throws Exception {
		GenericApplicationContext ctx = new GenericApplicationContext();
		new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(OVERRIDE_CONTEXT);
		SimpleMapScope scope = new SimpleMapScope();
		ctx.getBeanFactory().registerScope("request", scope);
		ctx.refresh();

		ITestBean bean = (ITestBean) ctx.getBean("testBean");
		assertThat(bean.getName()).isEqualTo("male");
		assertThat(bean.getAge()).isEqualTo(99);

		assertThat(scope.getMap().containsKey("scopedTarget.testBean")).isTrue();
		assertThat(scope.getMap().get("scopedTarget.testBean").getClass()).isEqualTo(TestBean.class);
	}
	

Spring Bean 自定义特性

Spring框架提供了许多接口,可用于自定义Bean特性。

生命周期回调

为了与容器对bean生命周期的管理进行交互,您可以实现Spring InitializingBean和DisposableBean接口。容器为前者调用afterPropertiesSet()并为后者调用destroy(),以使Bean在初始化和销毁​​Bean时执行某些操作。

JSR-250 @PostConstruct和@PreDestroy批注通常被认为是在现代Spring应用程序中接收生命周期回调的最佳实践。使用这些注释意味着您的bean没有耦合到特定于Spring的接口。有关详细信息,请参见使用@PostConstruct和@PreDestroy。
如果不想使用JSR-250批注,但仍然想删除耦合,请考虑使用init-method和destroy-method Bean定义元数据。

ApplicationContextAware and BeanNameAware

org.springframework.context.annotation.AnnotationConfigApplicationContext源码:

继承图;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gazOWPyz-1587892064597)(leanote://file/getImage?fileId=5ea3d418ab6441676901cb4b)]

实例化过程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j2D6Pm3M-1587892064601)(leanote://file/getImage?fileId=5ea3d418ab6441676901cb4a)]

Spring 注释扫描内部框架 手动注册自身bean:

org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

Aware 初始化

org.springframework.context.support.ApplicationContextAwareProcessor#invokeAwareInterfaces

启动和关机回调 Startup and Shutdown Callbacks

Lifecycle接口为具有自己的生命周期要求(例如启动和停止某些后台进程)的任何对象定义基本方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0mcjO8r6-1587892064603)(leanote://file/getImage?fileId=5ea45920ab64416769030979)]
任何Spring管理的对象都可以实现Lifecycle接口。然后,当ApplicationContext本身接收到启动和停止信号时(例如,对于运行时的停止/重新启动方案),它将把这些调用级联到在该上下文中定义的所有Lifecycle实现。它通过委派给LifecycleProcessor来做到这一点,如以下清单所示:

public interface LifecycleProcessor extends Lifecycle {

    void onRefresh();

    void onClose();
}

Spring 源码:

org.springframework.context.support.AbstractApplicationContext#finishRefresh

初始化LifeCycle

org.springframework.context.support.AbstractApplicationContext#initLifecycleProcessor

初始化 BeanPostProcess

org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory

BeanPostProcess

BeanPostProcessor接口定义了回调方法,您可以实施这些回调方法以提供自己的(或覆盖容器的默认值)实例化逻辑,依赖关系解析逻辑等。
如果您想在Spring容器完成实例化,配置和初始化bean之后实现一些自定义逻辑,则可以插入一个或多个自定义BeanPostProcessor实现

  • 系统初始化 第一步:允许在上下文子类中对bean工厂进行后处理
org.springframework.context.support.AbstractApplicationContext#postProcessBeanFactory

子类 实现 之一

org.springframework.web.context.support.GenericWebApplicationContext#postProcessBeanFactory
/**
	 * Register ServletContextAwareProcessor.
	 * @see ServletContextAwareProcessor
	 */
	@Override
	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);
	}
  • 调用在上下文中注册为bean的工厂处理器。
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
/**
	 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
	 * respecting explicit order if given.
	 * <p>Must be called before singleton instantiation.
	 */
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

委托实现类:

org.springframework.context.support.PostProcessorRegistrationDelegate  

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pp9IlW2m-1587892064606)(leanote://file/getImage?fileId=5ea4f71bfba2f45278000001)]

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q8faysGT-1587892064607)(leanote://file/getImage?fileId=5ea4f827fba2f45278000002)]

beforeSingletonCreation(beanName);
//默认设置不会新建 单例的Bean
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					singletonObject = singletonFactory.getObject();
				//当 getBean 不会获得时,注册标识为true
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton
/**
	 * Add the given singleton object to the singleton cache of this factory.
	 * <p>To be called for eager registration of singletons.
	 * @param beanName the name of the bean
	 * @param singletonObject the singleton object
	 */
	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);
		}
	}

创建Bean :

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

/**
	 * Central method of this class: creates a bean instance,
	 * populates the bean instance, applies post-processors, etc.
	 * @see #doCreateBean
	 */
	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
//Bean 定义文件
		RootBeanDefinition mbdToUse = mbd;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target 
			//依赖BeanPostProcess生成Java带路对象
			bean instance.
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

  • 注册拦截Bean创建的BeanProcess。
org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors

ApplicationListener 检测BeanPostProcess

org.springframework.beans.factory.config.ConfigurableBeanFactory#addBeanPostProcessor
254:		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

  • Bean 初始化后的 BeanPostProcess

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object,
org.springframework.beans.factory.support.RootBeanDefinition)

//继承了 BeanPostProcess 的 初始化
	if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
//使用 @PostConstruct 初始化
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

如果使用的是注解

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods

ApplicationListener

Interface to be implemented by application event listeners.
 * Based on the standard {@code java.util.EventListener} interface
 * for the Observer design pattern.
 *
 * <p>As of Spring 3.0, an ApplicationListener can generically declare the event type
 * that it is interested in. When registered with a Spring ApplicationContext, events
 * will be filtered accordingly, with the listener getting invoked for matching event
 * objects only.
google翻译
由应用程序事件侦听器实现的接口。 *基于观察者设计模式的标准{@code java.util.EventListener}接口。 * * <p>从Spring 3.0开始,ApplicationListener可以一般性地声明它感兴趣的事件类型*。在Spring ApplicationContext中注册时,事件*将被相应地过滤,而侦听器将被调用以匹配事件*对象
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
// Instantiate all remaining (non-lazy-init)singletons
//初始化非懒加载的单例Bean.
877:		beanFactory.preInstantiateSingletons();
org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons

实现:

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

Spring Aop 代理对象 生成

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
/**
	 * Apply before-instantiation post-processors, resolving whether there is a
	 * before-instantiation shortcut for the specified bean.
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean
	 * @return the shortcut-determined bean instance, or {@code null} if none
	 */
	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
//属性可见性 公开的 才可以初始化
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
//返回此bean定义是否是“合成的”,即*不是由应用程序本身定义的。  且返回此工厂是否拥有InstantiationAwareBeanPostProcessor *,它将在关机时应用於单例bean。
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor。
该接口的语义与BeanPostProcessor的语义相似,但有一个主要区别:BeanFactoryPostProcessor对Bean配置元数据进行操作。
也就是说,Spring IoC容器允许BeanFactoryPostProcessor读取配置元数据,并有可能在容器实例化除BeanFactoryPostProcessor实例以外的任何bean之前更改它。

您可以配置多个BeanFactoryPostProcessor实例,并且可以通过设置order属性来控制这些BeanFactoryPostProcessor实例的运行顺序。但是,仅当BeanFactoryPostProcessor实现Ordered接口时,才可以设置此属性。如果您编写自己的BeanFactoryPostProcessor,则也应该考虑实现Ordered接口。有关更多详细信息,请参见BeanFactoryPostProcessor和Ordered接口的javadoc。

Using Filters to Customize Scanning 自定义扫描器

Filter Type Example Expression Description Google 翻译
annotation (default) org.example.SomeAnnotation An annotation to be present or meta-present at the type level in target components. 在目标组件中的类型级别上存在或元存在的注释。
assignable org.example.SomeClass A class (or interface) that the target components are assignable to (extend or implement). 目标组件可分配给(扩展或实现)的类(或接口)。
aspectj org.example…*Service+ An AspectJ type expression to be matched by the target components. 目标组件要匹配的AspectJ类型表达式。
regex org.example.Default.* A regex expression to be matched by the target components’ class names. 要与目标组件的类名匹配的正则表达式。
custom org.example.MyTypeFilter A custom implementation of theorg.springframework.core.type.TypeFilterinterface.org.springframework.core.type.TypeFilter 接口的自定义实现。
@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}

@Configuration

常规Spring组件中的@Bean方法的处理方式与Spring @Configuration类中的@Bean方法不同。区别在于@Component类没有使用CGLIB增强,无法拦截方法和字段的调用。CGLIB代理是调用@Configuration类中@Bean方法中的方法或字段的方法,用于创建Bean元数据引用来协作对象。此类方法不是用普通的Java语义调用的,而是通过容器进行的,以提供Spring Bean的常规生命周期管理和代理,即使通过@Bean方法的编程调用引用其他Bean时也是如此。相反,在普通@Component类内的@Bean方法中调用方法或字段具有标准Java语义,而无需特殊的CGLIB处理或其他约束。

Spring Bean 自动命名

若在 @Component, @Repository, @Service, and @Controller 等 提供了 bean 名称 ,Spring 则使用自定义名称 ,否则 使用才用自动命名(默认 为 类名首字母小写)

如果不想依赖默认的Bean命名策略,则可以提供自定义Bean命名策略。首先,实现BeanNameGenerator接口,并确保包括默认的无参数构造函数。然后,在配置扫描程序时提供完全限定的类名,如以下示例注释和Bean定义所示。
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
    // ...
}

生成候选组件的索引

尽管类路径扫描非常快,但是可以通过在编译时创建候选静态列表来提高大型应用程序的启动性能。在这种模式下,作为组件扫描目标的所有模块都必须使用此机制。

您现有的@ComponentScan或<context:component-scan指令必须保留原样,以请求上下文扫描某些程序包中的候选对象。当ApplicationContext检测到这样的索引时,它将自动使用它而不是扫描类路径。
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.2.5.RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>

该过程将生成一个包含在jar文件中的META-INF / spring.components文件。

在类路径上找到META-INF / spring.components时,将自动启用索引。如果某些库(或用例)的索引部分可用,但无法为整个应用程序构建,则可以通过将spring.index.ignore设置为来回退到常规的类路径安排(好像根本没有索引)。true,可以是系统属性,也可以是classpath根目录下的spring.properties文件。

使用AnnotationConfigWebApplicationContext支持Web应用程序

AnnotationConfigApplicationApplicationContext的WebApplicationContext变体可用于AnnotationConfigWebApplicationContext。在配置Spring ContextLoaderListener Servlet侦听器,Spring MVC DispatcherServlet等时,可以使用此实现。以下web.xml代码段配置了一个典型的Spring MVC Web应用程序(请注意contextClass context-param和init-param的使用):
<web-app>
    <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
        instead of the default XmlWebApplicationContext -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>

    <!-- Configuration locations must consist of one or more comma- or space-delimited
        fully-qualified @Configuration classes. Fully-qualified packages may also be
        specified for component-scanning -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.acme.AppConfig</param-value>
    </context-param>

    <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Declare a Spring MVC DispatcherServlet as usual -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
            instead of the default XmlWebApplicationContext -->
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <!-- Again, config locations must consist of one or more comma- or space-delimited
            and fully-qualified @Configuration classes -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.acme.web.MvcConfig</param-value>
        </init-param>
    </servlet>

    <!-- map all requests for /app/* to the dispatcher servlet -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
</web-app>

注册 LoadTimeWeaver

Spring使用LoadTimeWeaver在将类加载到Java虚拟机(JVM)中时对其进行动态转换。

要启用加载时编织,可以将@EnableLoadTimeWeaving添加到您的@Configuration类之一,如以下示例所示:

@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}

为ApplicationContext配置后,该ApplicationContext中的任何bean都可以实现LoadTimeWeaverAware,从而接收到对加载时间weaver实例的引用。与Spring的JPA支持结合使用时,该功能特别有用,因为在JPA类转换中可能需要进行加载时编织。有关更多详细信息,请查阅LocalContainerEntityManagerManagerBean javadoc。有关AspectJ加载时编织的更多信息,请参见Spring框架中的AspectJ加载时编织。

Spring 标准事件

Event Explanation Google 翻译
ContextRefreshedEvent Published when the ApplicationContext is initialized or refreshed (for example, by using the refresh() method on the ConfigurableApplicationContext interface). Here, “initialized” means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such “hot” refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not. 在初始化或刷新ApplicationContext时发布(例如,通过使用ConfigurableApplicationContext接口上的refresh()方法)。在这里,“已初始化”是指所有Bean均已加载,检测到并激活了后处理器Bean,已预先实例化单例并且可以使用ApplicationContext对象。只要尚未关闭上下文,只要选定的ApplicationContext实际上支持这种“热”刷新,就可以多次触发刷新。例如,XmlWebApplicationContext支持热刷新,但GenericApplicationContext不支持。
ContextStartedEvent Published when the ApplicationContext is started by using the start() method on the ConfigurableApplicationContext interface. Here, “started” means that all Lifecycle beans receive an explicit start signal. Typically, this signal is used to restart beans after an explicit stop, but it may also be used to start components that have not been configured for autostart (for example, components that have not already started on initialization). 在ConfigurableApplicationContext接口上使用start()方法启动ApplicationContext时发布。在这里,“启动”表示所有Lifecycle bean都收到一个明确的启动信号。通常,此信号用于在显式停止后重新启动Bean,但也可以用于启动尚未配置为自动启动的组件(例如,尚未在初始化时启动的组件)。
ContextStoppedEvent Published when the ApplicationContext is stopped by using the stop() method on the ConfigurableApplicationContext interface. Here, “stopped” means that all Lifecycle beans receive an explicit stop signal. A stopped context may be restarted through a start() call. 通过使用ConfigurableApplicationContext接口上的stop()方法停止ApplicationContext时发布。在这里,“已停止”表示所有Lifecycle bean都收到一个明确的停止信号。停止的上下文可以通过start()调用重新启动。
ContextClosedEvent Published when the ApplicationContext is being closed by using the close() method on the ConfigurableApplicationContext interface or via a JVM shutdown hook. Here, “closed” means that all singleton beans will be destroyed. Once the context is closed, it reaches its end of life and cannot be refreshed or restarted. 通过使用ConfigurableApplicationContext接口上的close()方法或通过JVM关闭钩子关闭ApplicationContext时发布。在这里,“封闭”意味着所有单例Bean将被销毁。关闭上下文后,它将达到使用寿命,无法刷新或重新启动。
RequestHandledEvent A web-specific event telling all beans that an HTTP request has been serviced. This event is published after the request is complete. This event is only applicable to web applications that use Spring’s DispatcherServlet. 一个特定于Web的事件,告诉所有Bean HTTP请求已得到服务。请求完成后,将发布此事件。此事件仅适用于使用Spring的DispatcherServlet的Web应用程序。
ServletRequestHandledEvent A subclass of RequestHandledEvent that adds Servlet-specific context information. RequestHandledEvent的子类,添加了特定于Servlet的上下文信息。
  • 事件发布
org.springframework.context.ApplicationEventPublisher
  • 事件监听
org.springframework.context.ApplicationListener
  • 基于注释的事件侦听器
public class BlackListNotifier {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    @EventListener
    public void processBlackListEvent(BlackListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
    @EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
    // ...
}
}
  • 异步侦听器
@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {
    // BlackListEvent is processed in a separate thread
}

BeanFactory

BeanFactory API为Spring的IoC功能提供了基础。它的特定合同主要用于与Spring的其他部分以及相关的第三方框架集成,并且其DefaultListableBeanFactory实现是更高级别的GenericApplicationContext容器中的关键委托。

BeanFactory和相关接口(例如BeanFactoryAware,InitializingBean,DisposableBean)是其他框架组件的重要集成点。通过不需要任何注释,甚至不需要反射,它们可以在容器及其组件之间进行非常有效的交互。应用程序级Bean可以使用相同的回调接口,但通常更喜欢通过注释或通过程序配置进行声明式依赖注入。

请注意,核心BeanFactory API级别及其DefaultListableBeanFactory实现不对配置格式或要使用的任何组件注释进行假设。所有这些风味都是通过扩展(例如XmlBeanDefinitionReader和AutowiredAnnotationBeanPostProcessor)引入的,并以核心元数据表示形式对共享的BeanDefinition对象进行操作。这就是使Spring的容器如此灵活和可扩展的本质。

因为ApplicationContext包含BeanFactory的所有功能,所以通常建议在纯BeanFactory上使用,除非需要对Bean处理的完全控制。在ApplicationContext(例如GenericApplicationContext实现)中,按照约定(即,按bean名称或按bean类型(尤其是后处理器))检测到几种bean,而普通的DefaultListableBeanFactory则与任何特殊bean无关。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章