Spring8:一些常用的Spring Bean扩展接口
前言
Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心。
Spring框架运用了非常多的设计模式,从整体上看,它的设计严格遵循了OCP—-开闭原则,即:
1、保证对修改关闭,即外部无法修改Spring整个运作的流程
2、提供对扩展开放,即可以通过继承、实现Spring提供的众多抽象类与接口来改变类加载的行为
开卷有益,阅读Spring源码(无需每个类都看得很细,大体流程能梳理出来即可)对于个人水平的提升是帮助非常大的,同时也能在工作中即使发现和解决一些不常见的Spring问题。
不过,本文的目的不是整理Spring的流程,而是通过介绍一些常用的Spring Bean工具类,来让我们可以更好地使用Spring提供给开发者的多种特性,下面让我们开始吧。
InitialingBean和DisposableBean
InitialingBean是一个接口,提供了一个唯一的方法afterPropertiesSet()。
DisposableBean也是一个接口,提供了一个唯一的方法destory()。
这两个接口是一组的,功能类似,因此放在一起:前者顾名思义在Bean属性都设置完毕后调用afterPropertiesSet()方法做一些初始化的工作,后者在Bean生命周期结束前调用destory()方法做一些收尾工作。下面看一下例子,为了能明确地知道afterPropertiesSet()方法的调用时机,加上一个属性,给属性set方法,在set方法中打印一些内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/**
* @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
*/
public class LifecycleBean implements InitializingBean, DisposableBean
{
@SuppressWarnings ( "unused" )
private String lifeCycleBeanName;
public void setLifeCycleBeanName(String lifeCycleBeanName)
{
System.out.println( "Enter LifecycleBean.setLifeCycleBeanName(), lifeCycleBeanName = " + lifeCycleBeanName);
this .lifeCycleBeanName = lifeCycleBeanName;
}
public void destroy() throws Exception
{
System.out.println( "Enter LifecycleBean.destroy()" );
}
public void afterPropertiesSet() throws Exception
{
System.out.println( "Enter LifecycleBean.afterPropertiesSet()" );
}
public void beanStart()
{
System.out.println( "Enter LifecycleBean.beanStart()" );
}
public void beanEnd()
{
System.out.println( "Enter LifecycleBean.beanEnd()" );
}
}
|
配置一个spring.xml:
1
2
3
4
5
6
7
8
9
10
11
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
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.1.xsd">
< bean id = "lifeCycleBean" class = "org.xrq.bean.lifecycle.LifecycleBean" >
< property name = "lifeCycleBeanName" value = "lifeCycleBean" />
</ bean >
</ beans >
|
启动Spring容器,LifecycleBean执行的结果为:
1
2
3
4
5
|
Enter LifecycleBean.setLifeCycleBeanName(), lifeCycleBeanName = lifeCycleBean
Enter LifecycleBean.afterPropertiesSet()
Enter LifecycleBean.beanStart()
Enter LifecycleBean.destroy()
Enter LifecycleBean.beanEnd()
|
执行结果和我们想的一样,afterPropertiesSet()方法就如同它的名字所表示的那样,是在Bean的属性都被设置完毕之后,才会调用。
关于这两个接口,我总结几点:
1、InitializingBean接口、Disposable接口可以和init-method、destory-method配合使用,接口执行顺序优先于配置
2、InitializingBean接口、Disposable接口底层使用类型强转.方法名()进行直接方法调用,init-method、destory-method底层使用反射,前者和Spring耦合程度更高但效率高,后者解除了和Spring之间的耦合但是效率低,使用哪个看个人喜好
3、afterPropertiesSet()方法是在Bean的属性设置之后才会进行调用,某个Bean的afterPropertiesSet()方法执行完毕才会执行下一个Bean的afterPropertiesSet()方法,因此不建议在afterPropertiesSet()方法中写处理时间太长的方法
BeanNameAware、ApplicationContextAware和BeanFactoryAware
这三个接口放在一起写,是因为它们是一组的,作用相似。
“Aware”的意思是”感知到的”,那么这三个接口的意思也不难理解:
1、实现BeanNameAware接口的Bean,在Bean加载的过程中可以获取到该Bean的id
2、实现ApplicationContextAware接口的Bean,在Bean加载的过程中可以获取到Spring的ApplicationContext,这个尤其重要,ApplicationContext是Spring应用上下文,从ApplicationContext中可以获取包括任意的Bean在内的大量Spring容器内容和信息
3、实现BeanFactoryAware接口的Bean,在Bean加载的过程中可以获取到加载该Bean的BeanFactory
看一下例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/**
* @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
*/
public class AwareBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware
{
private String beanName;
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
public void setBeanName(String beanName)
{
System.out.println( "Enter AwareBean.setBeanName(), beanName = " + beanName + "\n" );
this .beanName = beanName;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
System.out.println( "Enter AwareBean.setApplicationContext(), applicationContext = " + applicationContext + "\n" );
this .applicationContext = applicationContext;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException
{
System.out.println( "Enter AwareBean.setBeanFactory(), beanfactory = " + beanFactory + "\n" );
this .beanFactory = beanFactory;
}
}
|
配置一个Spring.xml:
1
2
3
4
5
6
7
8
9
10
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
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.1.xsd">
< bean id = "AwareBean" class = "org.xrq.bean.aware.AwareBean" />
</ beans >
|
启动Spring容器后的执行结果为:
1
2
3
4
5
|
Enter AwareBean.setBeanName(), beanName = AwareBean
Enter AwareBean.setBeanFactory(), beanfactory = org.springframework.beans.factory.support.DefaultListableBeanFactory@2747fda0: defining beans [AwareBean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor]; root of factory hierarchy
Enter AwareBean.setApplicationContext(), applicationContext = org.springframework.context.support.GenericApplicationContext@5514cd80: startup date [Mon Aug 08 19:23:30 CST 2016]; root of context hierarchy
|
关于这三个接口以及上面的打印信息,总结几点:
1、如果你的BeanName、ApplicationContext、BeanFactory有用,那么就自己定义一个变量将它们保存下来,如果没用,那么只需要实现setXXX()方法,用一下Spring注入进来的参数即可
2、如果Bean同时还实现了InitializingBean,容器会保证BeanName、ApplicationContext和BeanFactory在调用afterPropertiesSet()方法被注入
FactoryBean
FactoryBean在Spring中是非常有用的,使用Eclipse/MyEclipse的朋友可以对FactoryBean使用ctrl+t查看一下,FactoryBean这个接口在Spring容器中有大量的子实现。
传统的Spring容器加载一个Bean的整个过程,都是由Spring控制的,换句话说,开发者除了设置Bean相关属性之外,是没有太多的自主权的。FactoryBean改变了这一点,开发者可以个性化地定制自己想要实例化出来的Bean,方法就是实现FactoryBean接口。
看一下代码例子,为了讲清楚FactoryBean,内容相对多一些,首先定义一个接口Animal:
1
2
3
4
|
public interface Animal
{
public void move();
}
|
定义两个实现类Monkey和Tiger:
1
2
3
4
5
6
7
|
public class Monkey implements Animal
{
public void move()
{
System.out.println( "Monkey move!" );
}
}
|
1
2
3
4
5
6
7
|
public class Tiger implements Animal
{
public void move()
{
System.out.println( "Tiger move!" );
}
}
|
写一个实现类,实现FactoryBean接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
/**
* @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
*/
public class AnimalFactoryBean implements FactoryBean<Animal>
{
private String animal;
public Animal getObject() throws Exception
{
if ( "Monkey" .equals(animal))
{
return new Monkey();
}
else if ( "Tiger" .equals(animal))
{
return new Tiger();
}
else
{
return null ;
}
}
public Class<?> getObjectType()
{
return Animal. class ;
}
public boolean isSingleton()
{
return true ;
}
public void setAnimal(String animal)
{
this .animal = animal;
}
}
|
配置一个spring.xml,注入属性Tiger:
1
2
3
4
5
6
7
8
9
10
11
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
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.1.xsd">
< bean id = "animal" class = "org.xrq.bean.factory.AnimalFactoryBean" >
< property name = "animal" value = "Tiger" />
</ bean >
</ beans >
|
写一个JUnit的测试类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@RunWith (SpringJUnit4ClassRunner. class )
@ContextConfiguration (locations = {
"classpath*:spring.xml" ,
})
public class BaseTest
{
@Resource
private Animal animal;
@Test
public void aa()
{
animal.move();
}
}
|
查看一下运行结果:
1
|
Tiger move!
|
看到最后得到的并不是FactoryBean本身,而是FactoryBean的泛型对象,这就是FactoryBean的作用。FactoryBean的几个方法:
1、getObject()方法是最重要的,控制Bean的实例化过程
2、getObjectType()方法获取接口返回的实例的class
3、isSingleton()方法获取该Bean是否为一个单例的Bean
像我这段代码的功能就是传入一个String类型的参数,可以动态控制生成出来的是接口的哪种子类。有了FactoryBean,同样的我们也可以灵活地操控Bean的生成。
BeanPostProcessor
之前的InitializingBean、DisposableBean、FactoryBean包括init-method和destory-method,针对的都是某个Bean控制其初始化的操作,而似乎没有一种办法可以针对每个Bean的生成前后做一些逻辑操作,PostProcessor则帮助我们做到了这一点,先看一个简单的BeanPostProcessor。
网上有一张图画了Bean生命周期的过程,画得挺好,原图出处:
BeanPostProcess接口有两个方法,都可以见名知意:
1、postProcessBeforeInitialization:在初始化Bean之前
2、postProcessAfterInitialization:在初始化Bean之后
值得注意的是,这两个方法是有返回值的,不要返回null,否则getBean的时候拿不到对象。
写一段测试代码,首先定义一个普通的Bean,为了后面能区分,给Bean加一个属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class CommonBean
{
private String commonName;
public void setCommonName(String commonName)
{
this .commonName = commonName;
}
public void initMethod()
{
System.out.println( "Enter CommonBean.initMethod(), commonName = " + commonName);
}
}
|
定义一个PostProcess,实现BeanPostProcess接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
*/
public class PostProcessorBean implements BeanPostProcessor
{
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
System.out.println( "Enter ProcessorBean.postProcessAfterInitialization()\n" );
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
System.out.println( "Enter ProcessorBean.postProcessBeforeInitialization()" );
return bean;
}
}
|
配置一个spring.xml,给CommonBean的commonName赋予不同的值以区分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
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.1.xsd">
< bean id = "common0" class = "org.xrq.bean.common.CommonBean" init-method = "initMethod" >
< property name = "commonName" value = "common0" />
</ bean >
< bean id = "common1" class = "org.xrq.bean.common.CommonBean" init-method = "initMethod" >
< property name = "commonName" value = "common1" />
</ bean >
< bean id = "postProcessorBean" class = "org.xrq.bean.processor.PostProcessorBean" />
</ beans >
|
运行一个Spring容器, 初始化结果为:
1
2
3
4
5
6
7
8
9
10
|
Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common0
Enter ProcessorBean.postProcessAfterInitialization()
Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common1
Enter ProcessorBean.postProcessAfterInitialization()
Enter ProcessorBean.postProcessBeforeInitialization()
Enter ProcessorBean.postProcessAfterInitialization()
|
看到每个Bean初始化前后都会分别执行postProcessorBeforeInitiallization()方法与postProcessorAfterInitialization()方法,最后两行出现原因是,PostProcessorBean本身也是一个Bean。
BeanFactoryPostProcessor
接下来看另外一个PostProcessor—-BeanFactoryPostProcessor。
Spring允许在Bean创建之前,读取Bean的元属性,并根据自己的需求对元属性进行改变,比如将Bean的scope从singleton改变为prototype,最典型的应用应当是PropertyPlaceholderConfigurer,替换xml文件中的占位符,替换为properties文件中相应的key对应的value,这将会在下篇文章中专门讲解PropertyPlaceholderConfigurer的作用及其原理。
BeanFactoryPostProcessor就可以帮助我们实现上述的功能,下面来看一下BeanFactoryPostProcessor的使用,定义一个BeanFactoryPostProcessor的实现类:
1
2
3
4
5
6
7
8
9
10
11
|
/**
* @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
*/
public class FactoryPostProcessorBean implements BeanFactoryPostProcessor
{
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurablelistablebeanfactory)
throws BeansException
{
System.out.println( "Enter FactoryPostProcessorBean.postProcessBeanFactory()\n" );
}
}
|
spring.xml里面配置一下这个Bean,就不写了,运行一下Spring容器,结果为:
1
2
3
4
5
6
7
8
9
10
11
12
|
Enter FactoryPostProcessorBean.postProcessBeanFactory()
Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common0
Enter ProcessorBean.postProcessAfterInitialization()
Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common1
Enter ProcessorBean.postProcessAfterInitialization()
Enter ProcessorBean.postProcessBeforeInitialization()
Enter ProcessorBean.postProcessAfterInitialization()
|
从执行结果中可以看出两点:
1、BeanFactoryPostProcessor的执行优先级高于BeanPostProcessor
2、BeanFactoryPostProcessor的postProcessBeanFactory()方法只会执行一次
注意到postProcessBeanFactory方法是带了参数ConfigurableListableBeanFactory的,这就和我之前说的可以使用BeanFactoryPostProcessor来改变Bean的属性相对应起来了。ConfigurableListableBeanFactory功能非常丰富,最基本的,它携带了每个Bean的基本信息,比如我简单写一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/**
* @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
*/
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurablelistablebeanfactory)
throws BeansException
{
BeanDefinition beanDefinition = configurablelistablebeanfactory.getBeanDefinition( "common0" );
MutablePropertyValues beanProperty = beanDefinition.getPropertyValues();
System.out.println( "scope before change:" + beanDefinition.getScope());
beanDefinition.setScope( "singleton" );
System.out.println( "scope after change:" + beanDefinition.getScope());
System.out.println( "beanProperty:" + beanProperty);
}
|
看一下执行结果:
1
2
3
|
scope before change:
scope after change:singleton
beanProperty:PropertyValues: length=1; bean property 'commonName'
|
这样就获取了Bean的生命周期以及重新设置了Bean的生命周期。ConfigurableListableBeanFactory还有很多的功能,比如添加BeanPostProcessor,可以自己去查看。
InstantiationAwareBeanPostProcessor
最后写一个叫做InstantiationAwareBeanPostProcessor的PostProcessor。
InstantiationAwareBeanPostProcessor又代表了Spring的另外一段生命周期:实例化。先区别一下Spring Bean的实例化和初始化两个阶段的主要作用:
1、实例化—-实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中
2、初始化—-初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性
之前的BeanPostProcessor作用于过程(2)前后,现在的InstantiationAwareBeanPostProcessor则作用于过程(1)前后,看一下代码,给前面的CommonBean加上构造函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class CommonBean
{
public CommonBean()
{
System.out.println( "Enter CommonBean's constructor" );
}
private String commonName;
public void setCommonName(String commonName)
{
System.out.println( "Enter CommonBean.setCommonName(), commonName = " + commonName);
this .commonName = commonName;
}
public void initMethod()
{
System.out.println( "Enter CommonBean.initMethod(), commonName = " + commonName);
}
}
|
实现InstantiationAwareBeanPostProcessor接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
/**
* @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
*/
public class InstantiationAwareBeanPostProcessorBean implements InstantiationAwareBeanPostProcessor
{
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
System.out.println( "Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInitialization()" );
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
System.out.println( "Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInitialization()" );
return bean;
}
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException
{
System.out.println( "Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInstantiation()" );
return true ;
}
public Object postProcessBeforeInstantiation(Class<?> bean, String beanName) throws BeansException
{
System.out.println( "Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInstantiation()" );
return null ;
}
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pd, Object bean,
String beanName) throws BeansException
{
return pvs;
}
}
|
配置一下spring.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
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.1.xsd">
< bean id = "common" class = "org.xrq.bean.common.CommonBean" >
< property name = "commonName" value = "common" />
</ bean >
< bean class = "org.xrq.bean.processor.InstantiationAwareBeanPostProcessorBean" />
</ beans >
|
启动容器,观察一下运行结果为:
1
2
3
4
5
6
7
8
9
|
Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInstantiation()
Enter CommonBean's constructor
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInstantiation()
Enter CommonBean.setCommonName(), commonName = common
Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInitialization()
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInitialization()
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInstantiation()
Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInitialization()
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInitialization()
|
最后三行的运行结果不去关注,看到很明显的,InstantiationAwareBeanPostProcessor作用的是Bean实例化前后,即:
1、Bean构造出来之前调用postProcessBeforeInstantiation()方法
2、Bean构造出来之后调用postProcessAfterInstantiation()方法
不过通常来讲,我们不会直接实现InstantiationAwareBeanPostProcessor接口,而是会采用继承InstantiationAwareBeanPostProcessorAdapter这个抽象类的方式来使用。
后记
如果只会写个Bean,配置在xml文件里面,注入一下,那是最最基础的Spring开发者。一个中级、高级的Spring开发者,必然会对Spring中的多个扩展点有所了解,并利用这些扩展点更好地为项目服务,使得整个代码结构更加地优雅,并且可读性、可维护性更好。
抛砖引玉,本文只是简单地介绍一些常用的Spring Bean扩展接口以及它们的简单用法,更深入的或者它们一些合适的使用场景,还需要留待网友朋友们自己去探索。
原文出处: 五月的仓颉
from: http://www.importnew.com/22775.html
Spring8:一些常用的Spring Bean扩展接口相关推荐
- java 扩展接口_详解常用的Spring Bean扩展接口
前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...
- Spring - BeanDefinitionRegistryPostProcessor 扩展接口 动态注册bean
文章目录 Pre org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor 接口的继承关系 BeanD ...
- Spring - InstantiationAwareBeanPostProcessor 扩展接口
文章目录 Pre org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor InstantiationA ...
- Spring - BeanFactoryPostProcessor 扩展接口
文章目录 Pre org.springframework.beans.factory.config.BeanFactoryPostProcessor 源码探究 1 是否实现BeanDefinition ...
- Spring - DisposableBean扩展接口
文章目录 Pre org.springframework.beans.factory.DisposableBean 使用场景 源码解析 扩展示例 Pre Spring Boot - 扩展接口一览 or ...
- Spring - ApplicationContextInitializer 扩展接口
文章目录 Pre org.springframework.context.ApplicationContextInitializer扩展点 扩展接口 扩展生效方式 方式一 : Spring SPI扩展 ...
- Spring Boot - 扩展接口一览
文章目录 扩展接口 扩展接口
- SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)
微信公众号:吉姆餐厅ak 学习更多源码知识,欢迎关注. SpringBoot2 | SpringBoot启动流程源码分析(一) SpringBoot2 | SpringBoot启动流程源码分析(二) ...
- 被各种注解搞晕了?那快来看看Spring Bean注解详解!
前言 本篇博客中,我们将会讨论用于声明不同类型 Beans 的几种最常用的 Spring Bean 注解. 众所周知,Spring 容器中有许多配置 Bean 的方法,我们既可以通过 XML 配置,也 ...
最新文章
- 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(二)
- JPA字段长度 Mysql数据库
- android ListView ListSelector 不起作用(被覆盖)
- Python Pandas General functions(静态方法)
- [ANE for Android]Java接口部分引用第三方JAR的解决办法
- C语言基础教程之强制类型转换
- 12个强大的Web服务测试工具
- 通信业正面临一场巨变,要么滚蛋要么改变
- [IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序...
- R语言机器学习中数据可视化的杀手锏
- 20170917软件工程师在线笔试之员工幸福感问题
- 深入解析 ext2 文件系统
- 30+简约和平铺的WordPress复古主题
- java webservice接口开发实例_Webservice 接口开发简单例子
- 中国占三分之一!CBinsights世界最新独角兽排名出炉
- javascript中map和filter的区别
- pci-e插槽gen2 x4 link什么意思
- IDEA中如何快速导包
- DLT645-2007 规约 电表 报文解析
- 【虚拟终端工具】SecureCRT工具连接虚拟机、rz/sz传输、中文乱码问题解决
热门文章
- Lesson 3.张量的广播和科学运算
- 金融反欺诈和金融构建信用评分或者金融预测特征抽取案例
- 完全图解RNN、RNN变体、Seq2Seq、Attention机制
- 信息检索与数据挖掘的常用加权技术。
- Learning to Rank 中Listwise关于ListNet算法讲解及实现
- Spring-使用外部属性文件01
- java接口示例_【基础篇】java-接口及其示例
- 学习笔记Kafka(二)—— Kafka安装配置(1)—— JDKZookeeper安装、Zookeeper 常用操作
- 爬虫学习笔记(二十四)—— pyspider框架
- java更新 位置_请求位置信息更新 | Android 开发者 | Android Developers