Spring基础IOC容器及常见注解
Posted 烟锁迷城
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring基础IOC容器及常见注解相关的知识,希望对你有一定的参考价值。
1、IOC基础
1.1、基础认知
IOC是指控制反转,即将创建Bean的权限交给容器,使用Bean的权限交给开发者。
在SpringBoot中,JAVA配置类的方式被广泛使用。
@Configuration 注解可以起到在Spring中XML配置的作用,@Bean注解提示要进行注入的bean。
@Bean注解可以声明注入的Bean在IOC容器中的名字,以进行调用。
@Configuration
public class JavaConfig {
@Bean
public User getUser(){
return new User();
}
@Bean({"a","b"})
public User getTest(){
return new User();
}
}
在测试类中,使用AnnotationConfigApplicationContext 调用Bean,在获取User被注入到容器中的实例时,默认的名字是被加了@Bean注解的方法名,如果声明过,则是声明后的名字。你可以在一个@Bean注解中声明多个名字,这些名字将指向同一个bean。
public class TeatMain {
@Test
public void test1() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
System.out.println(context.getBean("getUser", User.class));
System.out.println(context.getBean("a", User.class));
System.out.println(context.getBean("b", User.class));
}
}
1.2、原理解析
从ClassPathXmlApplicationContext获取配置信息,因为传入的this方法中parent参数为空,所以不需要关注super方法,因为super方法内会检测parent是否为空。
this.setConfigLocations(configLocations);方法会替代一些路径上的符号,关键方法是refresh。
ApplicationContext ac = new ClassPathXmlApplicationContext("");
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for(int i = 0; i < locations.length; ++i) {
this.configLocations[i] = this.resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}
refresh使用模板方法,关键方法是
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();,进行IOC容器的初始化操作。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
//IOC容器初始化操作
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
obtainFreshBeanFactory()方法中的
this.refreshBeanFactory()方法,刷新IOC容器
this.getBeanFactory();方法,获取Bean Factory对象,这意味着已经完成了IOC的初始化操作
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新IOC容器
this.refreshBeanFactory();
//获取Bean Factory对象
return this.getBeanFactory();
}
在refreshBeanFactory方法中,成功创建DefaultListableBeanFactory对象,然后this.loadBeanDefinitions(beanFactory);方法将有@Bean注解的类加载至BeanFactory中。
protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
//创建Bean Factory对象,即DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
//加载Bean Definitions,即加载@Bean注解的代码成为Bean
this.loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
} catch (IOException var2) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
}
}
reader.register(ClassUtils.toClassArray(this.componentClasses));方法将Bean注册至AnnotatedBeanDefinitionReader之中。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
AnnotatedBeanDefinitionReader reader = this.getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = this.getClassPathBeanDefinitionScanner(beanFactory);
BeanNameGenerator beanNameGenerator = this.getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", beanNameGenerator);
}
ScopeMetadataResolver scopeMetadataResolver = this.getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.componentClasses.isEmpty()) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Registering component classes: [" + StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
}
reader.register(ClassUtils.toClassArray(this.componentClasses));
}
if (!this.basePackages.isEmpty()) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Scanning base packages: [" + StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
String[] var7 = configLocations;
int var8 = configLocations.length;
for(int var9 = 0; var9 < var8; ++var9) {
String configLocation = var7[var9];
try {
Class<?> clazz = ClassUtils.forName(configLocation, this.getClassLoader());
if (this.logger.isTraceEnabled()) {
this.logger.trace("Registering [" + configLocation + "]");
}
reader.register(new Class[]{clazz});
} catch (ClassNotFoundException var13) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Could not load class for config location [" + configLocation + "] - trying package scan. " + var13);
}
int count = scanner.scan(new String[]{configLocation});
if (count == 0 && this.logger.isDebugEnabled()) {
this.logger.debug("No component classes found for specified class/package [" + configLocation + "]");
}
}
}
}
}
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);为最后的工具方法,将Bean注册其中。
public void register(Class... componentClasses) {
Class[] var2 = componentClasses;
int var3 = componentClasses.length;
for(int var4 = 0; var4 < var3; ++var4) {
Class<?> componentClass = var2[var4];
this.registerBean(componentClass);
}
}
public void registerBean(Class<?> beanClass) {
this.doRegisterBean(beanClass, (String)null, (Class[])null, (Supplier)null, (BeanDefinitionCustomizer[])null);
}
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
int var10;
int var11;
if (qualifiers != null) {
Class[] var9 = qualifiers;
var10 = qualifiers.length;
for(var11 = 0; var11 < var10; ++var11) {
Class<? extends Annotation> qualifier = var9[var11];
if (Primary.class == qualifier) {
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
} else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
BeanDefinitionCustomizer[] var13 = customizers;
var10 = customizers.length;
for(var11 = 0; var11 < var10; ++var11) {
BeanDefinitionCustomizer customizer = var13[var11];
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
这段为注册Bean的方法,主要是registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());方法。
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
其中最简单的,单例Bean的实现就是将所有的Bean都放入一个Map<String, BeanDefinition>结构的Map,Key为Bean的名字,Value为BeanDefinition。
其他Bean的实现方式可以自行研究探讨。
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(64);
public SimpleBeanDefinitionRegistry() {
}
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "'beanName' must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
this.beanDefinitionMap.put(beanName, beanDefinition);
}
1.3、实例化
实例化的方法核心代码为NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);
@Nullable
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
} else {
BeanFactory parent = this.getParentBeanFactory();
if (parent instanceof DefaultListableBeanFactory) {
return ((DefaultListableBeanFactory)parent).resolveBean(requiredType, args, nonUniqueAsNull);
} else if (parent != null) {
ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
if (args != null) {
return parentProvider.getObject(args);
} else {
return nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable();
}
} else {
return null;
}
}
}
String[] candidateNames = this.getBeanNamesForType(requiredType);方法获取beanDefinitionNames中全部的beanName。
获取到之后,进行循环获取,Object beanInstance = candidates.get(candidateName);方法进行实例化的操作。
@Nullable
private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
String[] candidateNames = this.getBeanNamesForType(requiredType);
String[] var6;
int var7;
int var8;
String beanName;
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList(candidateNames.length);
var6 = candidateNames;
var7 = candidateNames.length;
for(var8 = 0; var8 < var7; ++var8) {
beanName = var6[var8];
if (!this.containsBeanDefinition(beanName) || this.getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
if (candidateNames.length == 1) {
return this.resolveNamedBean(candidateNames[0], requiredType, args);
} else {
if (candidateNames.length > 1) {
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
var6 = candidateNames;
var7 = candidateNames.length;
for(var8 = 0; var8 < var7; ++var8) {
beanName = var6[var8];
if (this.containsSingleton(beanName) && args == null) {
Object beanInstance = this.getBean(beanName);
candidates.put(beanName, beanInstance instanceof NullBean ? null : beanInstance);
} else {
candidates.put(beanName, this.getType(beanName));
}
}
String candidateName = this.determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
candidateName = this.determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null) {
return null;
}
if (beanInstance instanceof Class) {
return this.resolveNamedBean(candidateName, requiredType, args);
}
return new NamedBeanHolder(candidateName, beanInstance);
}
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
return null;
}
}
在doGetBean方法中,Object sharedInstance = this.getSingleton(beanName);方法为获取单例Bean的方法,显然是核心逻辑。在这个方法中,获取到单例的Bean之后,如果不为空就正常返回,如果为空,则需要进行创建。
prototypeInstance = this.createBean(beanName, mbd, args);方法就是创建方法。
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object beanInstance;
if (sharedInstance != null && args == null) {
if (this.logger.isTraceEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
return parentBeanFactory.getBean(nameToLookup);
}
if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var12;
if (dependsOn != null) {
var12 = dependsOn;
int var13 = dependsOn.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dep = var12[var14];
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
this.registerDependentBean(dep, beanName);
try {
this.getBean(dep);
} catch (NoSuchBeanDefinitionException var31) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var31);
}
}
}
if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, () -> {
try {
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
var12 = null;
Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ��" + beanName + "'");
}
Scope scope = (Scope)this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
this.beforePrototypeCreation(beanName);
Object var4;
try {
var4 = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
return var4;
});
beanInstance = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var30) {
throw new ScopeNotActiveException(beanName, scopeName, var30);
}
}
} catch (BeansException var32) {
beanCreation.tag("exception", var32.getClass().toString());
beanCreation.tag("message", String.valueOf(var32.getMessage()));
this.cleanupAfterBeanCreationFailure(beanName);
throw var32;
} finally {
beanCreation.end();
}
}
return this.adaptBeanInstance(name, beanInstance, requiredType);
}
依然寻找DoGetBean方法进行查看
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
} catch (BeanDefinitionValidationException var9) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
}
Object beanInstance;
try {
beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
if (beanInstance != null) {
return beanInstance;
}
} catch (Throwable var10) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
}
try {
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
} catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
throw var7;
} catch (Throwable var8) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
}
}
找到instanceWrapper = this.createBeanInstance(beanName, mbd, args);方法,创建Bean的实例。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized(mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable var17) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
}
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
Object exposedObject = bean;
try {
this.populateBean(beanName, mbd, instanceWrapper);
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
if (earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
this.instantiateBean(beanName, mbd);方法是初始化Bean的方法。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
} else {
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return this.obtainFromSupplier(instanceSupplier, beanName);
} else if (mbd.getFactoryMethodName() != null) {
return this.instantiateUsingFactoryMethod(beanName, mbd, args);
} else {
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized(mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
} else {
Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
ctors = mbd.getPreferredConstructors();
return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
} else {
return this.autowireConstructor(beanName, mbd, ctors, args);
}
}
}
}
}
getInstantiationStrategy()显然是一个策略模式,具有三种不同的抽象方法。
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(() -> {
return this.getInstantiationStrategy().instantiate(mbd, beanName, this);
}, this.getAccessControlContext());
} else {
beanInstance = this.getInstantiationStrategy().instantiate(mbd, beanName, this);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
this.initBeanWrapper(bw);
return bw;
} catch (Throwable var5) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", var5);
}
}
其中第一种方法的实现是上段代码中使用过的。
public interface InstantiationStrategy {
Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3) throws BeansException;
Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3, Constructor<?> var4, Object... var5) throws BeansException;
Object instantiate(RootBeanDefinition var1, @Nullable String var2, BeanFactory var3, @Nullable Object var4, Method var5, Object... var6) throws BeansException;
}
return BeanUtils.instantiateClass(constructorToUse, new Object[0]);代码代表最终返回的结果为BeanUtils.instantiateClass方法的返回值。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
if (!bd.hasMethodOverrides()) {
Constructor constructorToUse;
synchronized(bd.constructorArgumentLock) {
constructorToUse = (Constructor)bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
clazz.getClass();
constructorToUse = (Constructor)AccessController.doPrivileged(() -> {
return clazz.getDeclaredConstructor();
});
} else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
} catch (Throwable var9) {
throw new BeanInstantiationException(clazz, "No default constructor found", var9);
}
}
}
return BeanUtils.instantiateClass(constructorToUse, new Object[0]);
} else {
return this.instantiateWithMethodInjection(bd, beanName, owner);
}
}
可以看到,return ctor.newInstance(argsWithDefaultValues);方法最后返回,那么ctor是构造器Constructor<T> ctor。
Constructor的newInstance方法,这个是反射的一种创建实例的方法,也就是说,IOC最终使用了代理来进行实例化。
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return BeanUtils.KotlinDelegate.instantiateClass(ctor, args);
} else {
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
for(int i = 0; i < args.length; ++i) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null;
} else {
argsWithDefaultValues[i] = args[i];
}
}
return ctor.newInstance(argsWithDefaultValues);
}
} catch (InstantiationException var6) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", var6);
} catch (IllegalAccessException var7) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var7);
} catch (IllegalArgumentException var8) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var8);
} catch (InvocationTargetException var9) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", var9.getTargetException());
}
}
2、注解
2.1、常用注解
注解名称 | 说明 |
@Configuration | 把一个类作为一个IOC容器,在某个方法上如果有@Bean注解,那么就会被作为spring容器的bean |
@ComponentScan | 在配置类上增加@ComponentScan注解,该注解会扫描该类所在的包下所有的配置类,相当于context:component-scan |
@Scope | 用于指定scope作用域的(用在类上) |
@Lazy | 表示延迟初始化 |
@Import | 导入外部资源 |
生命周期控制 | @PostConstruct:用于指定初始化方法(用在方法上) @PreDestory:用于指定销毁方法(用在方法上) @DependsOn:定义Bean初始化及销毁时的顺序 |
@Conditional | Spring4开始提供,它的作用是按照一定的条件进行判断,满足条件给容器注册Bean |
2.2、Conditional扩展注解
@Conditional扩展注解 | 作用(判断是否满足指定条件) |
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定的Bean |
@ConditionalOnMissingBean | 容器中不存在指定的Bean |
@ConditionalOnExpression | 满足Spel表达式 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定的资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnIndi | INDI存在指定项 |
2.3、泛值注解
注解名称 | 说明 |
@Component | 泛指组件,当组件不好归类的时候,可以使用该注解 |
@Service | 用于标注业务层组件 |
@Controller | 用于标注控制层组件 |
@Repository | 用于标注数据访问组件 |
@Value | 普通数据类型赋值 |
@Autowired | 默认按类型装配,如果想要按名称装配,可配合@Qualifier注解一起使用 |
@PropertySource | 读取配置文件赋值 |
@Qualifier | 如存在多个实例,配合使用以锁定某一个 |
@Primary | 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 |
@Resource | 默认按名称装配,当找不到与名称匹配的Bean时才按照类型装配 |
3、常用注解解析
3.1、@Autowired与@Resource,装配Bean
@Autowired注解的作用是按类型装配,无法按名称装配。如果想要用名称装配,需要配合@Qualifier注解使用。对于@Service等注解,加入容器的Bean的默认名称为类名首字母小写,所以可以这样使用
public class UserController{
@Autowired()
@Qualifier("userService")
private UserService userService;
}
@Service等注解可以不使用默认名称,@Service("service")可以声明指定名称
@Resource的作用与@Autowired相同,但是查找顺序不同,默认按名称装配,当找不到与名称匹配的Bean时才按照类型装配,如果指定名称,则只按照名称寻找。
3.2、@ComponentScan扫描需要加载Bean的目录
@ComponentScan注解的作用是扫描需要加载到容器中的配置类,可指定目录。在未指定时,默认会扫描当前目录及其子目录下的所有的被@Component,@Controller,@Service,@Repository注解修饰的类。
必须要与@Configuration配合使用才能生效。
vlaue:扫描地址
useDefaultFilters:是否使用默认过滤器(即@Component等注解)
excludeFilters:不使用的过滤注解
includeFilters:使用的过滤注解
@Configuration
@ComponentScan(value = {},
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(Controller.class)})
@ComponentScans注解是可以包含多个@ComponentScan注解的。
@Configuration
@ComponentScans({
@ComponentScan(
value = {},
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(Controller.class)})
})
3.3、@Primary首选项
@Primary注解可以将按照类型匹配时出现的多个符合项排出一个首选项。在有多个符合的匹配结果时,spring将会抛出错误org.springframework.beans.factory.NoUniqueBeanDefinitionException
@Configuration
public class JavaConfig {
@Bean
public User getUser() {
return new User();
}
@Bean
public User getTest() {
return new User();
}
}
public class TeatMain {
@Test
public void test1() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
System.out.println(context.getBean(User.class));
}
}
因为spring无法确定加载哪一个,但是增加@Primary修饰后,这个Bean将被列为首选项,优先加载。
@Configuration
public class JavaConfig {
@Bean
public User getUser() {
return new User();
}
@Bean
@Primary
public User getTest() {
return new User();
}
}
这样名为getTest的bean将被加载。
3.4、@Value赋值
@Value可以为bean的属性注入数值,需要配合@Component等可以加入IOC容器的注解使用。
- 普通的数值注入:@Value("yansuomicheng")
- 获取系统信息:@Value("#{systemProperties['os.name']}")
- 使用java函数获取随机数:@Value("#{T(java.lang.Math).random()*100}")
- 使用其他bean中的属性值:@Value("#{getUser.userName}")
- 加载配置文件:@Value("classpath:application.yml")
- 加载URL:@Value("http://www.baidu.com")
- 取得yml配置文件中的数值:@Value("${spring.application.name}")
@Component
public class Person {
//普通的数值注入
@Value("yansuomicheng")
private String name;
//获取系统信息
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName;
//使用java函数获取随机数
@Value("#{T(java.lang.Math).random()*100}")
private double randomNumber;
//使用其他bean中的属性值
@Value("#{getUser.userName}")
private String userName;
//加载配置文件
@Value("classpath:application.yml")
private Resource resourceFile;
//加载URL
@Value("http://www.baidu.com")
private Resource resourceUrl;
//取得yml配置文件中的数值
@Value("${spring.application.name}")
private String applicationName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSystemPropertiesName() {
return systemPropertiesName;
}
public void setSystemPropertiesName(String systemPropertiesName) {
this.systemPropertiesName = systemPropertiesName;
}
public double getRandomNumber() {
return randomNumber;
}
public void setRandomNumber(double randomNumber) {
this.randomNumber = randomNumber;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Resource getResourceFile() {
return resourceFile;
}
public void setResourceFile(Resource resourceFile) {
this.resourceFile = resourceFile;
}
public Resource getResourceUrl() {
return resourceUrl;
}
public void setResourceUrl(Resource resourceUrl) {
this.resourceUrl = resourceUrl;
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\\'' +
", systemPropertiesName='" + systemPropertiesName + '\\'' +
", randomNumber=" + randomNumber +
", userName='" + userName + '\\'' +
", resourceFile=" + resourceFile +
", resourceUrl=" + resourceUrl +
", applicationName='" + applicationName + '\\'' +
'}';
}
}
3.5、@PropertySource读取配置文件
@PropertySource主要作用是读取配置文件赋值,即上一个注解@Value想要读取配置文件中的数值时,需要增加这个注解才能确定需要读取到的配置文件
@Configuration
@PropertySource({"classpath:application.properties"})
public class JavaConfig {
@Bean
public User getUser() {
User user = new User();
user.setUserName("anyone");
return user;
}
@Bean
public Person getPerson() {
return new Person();
}
}
3.6、@Lazy延迟加载
@Lazy注解作用是延迟加载,当一个Bean增加了这个注解,在不被其他bean使用时,这个bean将不会被加载,直到它被使用。该注解可以减轻服务启动压力。
3.7、@PostConstruct系统初始化方法
@PostConstruct注解,用于指定在系统启动后开始执行的初始化方法,用在方法上。
3.8、@PreDestory系统关闭回调方法
@PreDestory注解,用于指定销毁方法,在系统结束时执行,
3.9、@DependsOn顺序指定
@DependsOn注解,定义Bean初始化及销毁时的顺序,可以放置多个,代表配置的Bean优先于当前Bean加载。
@DependsOn({"user"})
3.10、@Import
将类型加入到IOC容器的方法:
- 基于XML文件的方式<Bean>
- 基于XML文件的方式context:Component-Scan+@Component
- 基于java配置类@Bean
- 基于java配置类@ComponentScan+@Component
- FactoryBean+getObject方法
- @Import
@Import可以显式的引入需要的类型,可以以列表形式引入。
@Configuration
@Import({User.class,Person.class})
public class JavaConfig {
}
为更加灵活的引用,可以通过实现ImportSelector接口的方式动态引入
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{User.class.getName(), Person.class.getName()};
}
}
@Configuration
@Import(MyImportSelector.class)
public class JavaConfig {
}
也可以通过实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法来实现
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition user = new RootBeanDefinition(User.class);
RootBeanDefinition person = new RootBeanDefinition(Person.class);
registry.registerBeanDefinition("user",user);
registry.registerBeanDefinition("person",person);
}
}
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class JavaConfig {
}
3.11、@Conditional加载条件
条件判定,用来决定IOC是否加载这个类。通过实现condition接口实现matches方法,返回为true代表加载,false为不加载
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class ConditionalOnBean implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}
import com.example.demo.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JavaConfig {
@Bean
@Conditional(ConditionalOnBean.class)
public User user() {
return new User();
}
}
3.12、@Profile多环境解决方案
@Profile是@Condition注解的一种实现,可以选择加载某一个bean。
@Configuration
public class JavaConfig {
@Bean
@Profile("user")
public User user() {
return new User();
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("user");
context.register(JavaConfig.class);
context.refresh();
System.out.println(context.getBean(User.class));
3.13、@Scope决定Bean的作用域
- singleton:单例,在整个IOC中保持只有一个Bean。
- prototype:原型,在整个IOC中,每次调用都会创造一个新的Bean。
- request:在一次请求中,bean的生命周期与request同步。
- session:bean的生命周期与Session同步。
- 默认:即不使用时,单例。
以上是关于Spring基础IOC容器及常见注解的主要内容,如果未能解决你的问题,请参考以下文章