先看段代码:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
Class resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
/**1:当经历过resolveBeforeInstantiation方法后,
程序有两个选择,如果创建了代理或者说重写了
InstantiationAwareBeanPostProcessor的
postProcessBeforeInstantiation方法并在方法
postProcessBeforeInstantiation中改变了bean,则直接返回就可以了,
否则需要进行常规bean的创建。
*/
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 {
//常规bean的创建
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
本篇文章主要分析doCreateBean方法,这个是常规bean的创建,代码注释安排:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//1.如果是单例则需要首先清除缓存
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//2.根据指定bean使用对应的策略创建新的实例,例如:工厂方法、构造函数自动注入、简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//3.bean合并后的处理,Autowired注解正是通过此方法实现诸如类型的预解析
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//4.是否需要提早曝光:是单例 并且 允许循环依赖 并且 当前bean正在创建中,检测循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//addSingletonFactory:为了避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂缓存
//getEarlyBeanReference:对bean再一次依赖引用,SmartInstantiationAwareBeanPostProcessor,其中我们熟知的AOP就是在这里将advice动态织入bean中,若没有则直接返回bean,不做任何处理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//5.对bean进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean
populateBean(beanName, mbd, instanceWrapper);
//5下.调用初始化方法,比如init-method,初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//6.earlySingtonReference只有在检测到有循环依赖的情况下才会不为空
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
//如果exposedObject没有在初始化方法中被改变,也就是没有被增强
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
//检测依赖
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
//因为bean创建后其所依赖的bean一定是已经创建的,actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有全部创建完,也就是说存在循环依赖
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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
//7.根据scope注册DisposableBean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
//8.返回创建好的bean
return exposedObject;
}
接下来看下doCreateBean方法的概要思路:
(1)如果是单例则需要首先清除缓存(至于什么时候进行put,现在说为时尚早,以后更到那一篇的时候会说,这里留意下)。
(2)实例化bean,将BeanDefinition转换为BeanWrapper。转换是一个复杂的过程,大概分为这几步:
1.如果存在工厂方法则使用工厂方法进行初始化。
2.一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造函数并进行初始化。
3.如果既不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行bean的实例化。
(3)MergedBeanDefinitionPostProcessor的应用,bean合并后的处理,Autowired注解正是通过此方法实现诸如类型的预解析。
(4)循环依赖处理。
(5)属性填充,将所有的属性填充到bean的实例中。
(6)循环依赖检查。
(7)注册DisposableBean,如果配置了destroy-method,这里需要注册以便于在销毁的时候调用。
(8)完成创建并返回。
接下来对doCreateBean方法中重要的几步进行分析:
一、首先看createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 解析class
Class beanClass = resolveBeanClass(mbd, beanName);
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());
}
Supplier instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工厂方法不为空则使用工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
/**一个类有多个构造函数,
每个构造函数都有不同的参数,
所以调用前需要先根据参数锁定构造函数或者对应的工厂方法*/
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
//如果已经解析过则使用解析好的构造函数方法,不需要再次锁定
if (resolved) {
if (autowireNecessary) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
//使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
}
// 需要根据参数解析构造函数
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
//翻一下,没有特殊的处理,简单使用无参构造
return instantiateBean(beanName, mbd);
}
概括下createBeanInstance方法做了什么:
(1)mbd.getFactoryMethodName() != null意思就是如果在RootBeanDefinition中存在factoryMethodName属性,或者说在配置文件中配置了factory-method,那么spring会根据RootBeanDefinition中的配置使用instantiateUsingFactoryMethod方法生成bean的实例。
(2)解析构造函数并进行构造函数的实例化,一个bean可能对应多个构造函数,每个构造函数的参数不同,spring会根据参数个数及类型去判断最终会使用哪个构造函数进行实例化,但是这个判断过程很耗性能,所以这里用了缓存的机制,也就是判断resolvedConstructorOrFactoryMethod(看字面意思就知道:已经被解析的构造函数或者工厂方法)不为空就说明解析过了,直接取出来用就行了,如果缓存中没取到,就需要去解析构造函数,然后存入缓存以便下次使用。
看完createBeanInstance方法后你觉得里面哪个方法比较重要?其中有两个方法肯定给你留下了很深的印象,一个是autowireConstructor,另外一个是instantiateBean,因为最后不管构造函数解析过没解析过,都是走的这俩方法中的其中一个,发现了没?autowireConstructor这个方法是带有参数的实例化,意思就是用有参构造的进行实例化,而instantiateBean这个走的就是默认的无参构造了。
1.1、首先看下autowireConstructor方法
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor[] chosenCtors, @Nullable Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
//如果getBean方法调用的时候指定方法参数那么直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
//如果在getBean方法调用的时候没有指定则尝试从配置文件中解析
Object[] argsToResolve = null;
//尝试从缓存中获取
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
//从缓存中取
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
//配置的构造函数参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
//如果缓存中存在
if (argsToResolve != null) {
/**解析参数类型,如给定方法的构造函数是A("1","1"),
那么通过此方法后就会把配置中的("1","1")转换为(1,1),
当然,缓存中的值可能是原始值也可能是最终值*/
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
//没有被缓存
if (constructorToUse == null) {
// 需要解析构造函数
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
//提取配置文件中配置的构造函数参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
//用户承载解析后的构造函数参数的值
resolvedValues = new ConstructorArgumentValues();
//能解析到的参数的个数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 获取所有的构造函数
Constructor[] candidates = chosenCtors;
if (candidates == null) {
Class beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
/**将给定的构造函数排序,
先public类型的构造函数根据参数数量降序排序,
然后不是public的构造函数按参数数量降序排序*/
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set> ambiguousConstructors = null;
LinkedList causes = null;
for (Constructor candidate : candidates) {
Class[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
/**如果已经找到选用的构造函数或者
需要的参数个数小于当前的构造函数参数个数则终止,
因为已经按照参数个数降序排列*/
break;
}
if (paramTypes.length < minNrOfArgs) {
/**当前的构造函数个数小于需要的参数个数,就继续,
因为构造函数肯定得让这些参数全部传进去啊*/
continue;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
//有参数则根据值构造对应参数类型的参数
try {
//注释上获取参数的名称
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
//获取参数名称探索器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
//获取指定构造函数的参数名称
paramNames = pnd.getParameterNames(candidate);
}
}
//根据名称和数据类型创建参数持有者
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
//构造函数没有参数的情况
argsHolder = new ArgumentsHolder(explicitArgs);
}
//探测是否有不确定性的构造函数存在,例如不同构造函数的参数为父子关系
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
//如果它代表着当前最接近的匹配则选择作为构造函数
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
if (explicitArgs == null) {
//将解析的构造函数加入缓存
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
try {
final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction) () ->
strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
beanFactory.getAccessControlContext());
}
else {
beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
//将创建的实例加入BeanWrapper中
bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
autowireConstructor有点长,接下来总结下这个方法的大概运行流程:
(1)确定构造函数的参数,分为三步:
1.如果传入的explicitArgs不为空,就可以直接确定参数,因为explicitArgs参数是在调用Bean的时候用户指定的。
2.如果构造函数参数已经记录在缓存里的话,那么可以直接拿来用,这里要注意一点就是缓存中的参数类型不一定是最终类型,如果不是最终类型的话需要转换下类型。
3.如果前两步都获取不到的话就从配置文件配置的构造函数获取,通过BeanDefinition中的getConstructorArgumentValues获取后,再调用resolveConstructorArguments解析得到参数。
(2)确定构造函数,上一步已经确定了构造函数的参数,这一步需要根据这些参数锁定对应的构造函数,匹配的方法就是根据参数个数匹配。
(3)根据确定好的构造函数转换对应的参数类型,比如你的参数是Integer的,但是构造函数需要String的,这时候你得转换成String的才能传入构造函数。
(4)再次验证构造函数,因为有时候就算构造函数,参数名称和类型以及值都确定后也不一定直接锁定构造函数,不同构造函数的参数为父子关系,所以Spring在最后又做了一步验证。
(5)根据实例化策略以及得到得构造函数及构造函数参数实例化Bean。
1.2、然后看下instantiateBean方法
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
这个方法其实就是利用无参构造对bean进行实例化的,无参构造和有参
构造哪个简单?肯定是无参的了,所以这个方法里就直接对bean进行实例 了。其实仔细看下实例化的方法,是这么一段代码:
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
接下来就看看这个instantiate方法具体是怎么进行实例化的:
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
/**
如果有需要覆盖或者动态替换的方法则当然需要使用cglib进行动态代理,
因为可以在创建代理的同时将动态方法织入类中,但是如果没有需要动态改变
的方法,为了方便直接使用反射就可以了
*/
if (!bd.hasMethodOverrides()) {
Constructor constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
大概总结下instantiate这个方法,首先判断
!bd.hasMethodOverrides(),如果是true,说明用户没有使用
replace或lookup的配置方法,这时候就直接使用反射,简单快捷,但是 如果使用了这两个特性,就需要使用动态代理的方式将包含两个特性所对应 的逻辑拦截增强器设置进去。
二、接下来看doCreateBean方法中的第四个注释
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//addSingletonFactory:为了避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂缓存
//getEarlyBeanReference:对bean再一次依赖引用,SmartInstantiationAwareBeanPostProcessor,其中我们熟知的AOP就是在这里将advice动态织入bean中,若没有则直接返回bean,不做任何处理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
earlySingletonExposure表示是否提前曝光,有三个条件决定这个
变量的值,当前bean的scope是单例并且允许循环依赖并且当前单例bean正 在被创建。然后往下看,最关键的一句代码来了,getEarlyBeanReference这个方法是什么?你还记得循环依赖怎么解决的 吗?是不是从singletonFactories中取出来一个singletonFactory
,然后调用了singletonFactory的getObject方法,其中这个getObject 方法就是这个getEarlyBeanReference,这里java8的lambda表达式有点 迷惑性,addSingletonFactory用jdk7表示如下:
addSingletonFactory(beanName, new ObjectFactory(){
public Object getObject() throws BeansException{
return getEarlyBeanReference(beanName, mbd, bean);
}
});
然后看下getEarlyReference方法的代码:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
看见没,循环依赖能解决的根本原理就是返回了一个未创建完成的A, ,而且这个A还是一开始创建时候那个半成品的A,简单画个图:
三、继续看populateBean方法
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
return;
}
}
/**给InstantiationAwareBeanPostProcessors最后一次机会
在属性设置前来改变bean
*/
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//返回值为是否继续填充bean
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
//如果后处理器发出停止填充命令则终止后续的执行
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
//根据名称注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
//根据类型注入
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
//后处理器已经初始化
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//需要依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//对所有需要依赖检查的属性进行后处理
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
//依赖检查,对应的depends-on属性
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
//将属性应用到bean中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
总结下populateBean中的大概逻辑:
1.InstantiationAwareBeanPostProcessor处理器的
postProcessAfterInstantiation函数的应用,此函数可以控制程序
是否继续进行属性填充。 2.根据注入类型(byName/byType),提取依赖的bean,并统一存入 propertyValues中。 3.应用InstantiationAwareBeanPostProcessor处理器的 postProcessPropertyValues方法,对属性获取完毕填充前对属性的 再次处理。 4.将所有PropertyValues中的属性填充至BeanWrapper中。
四、继续看 initializeBean 方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
//对诸如Aware、BeanClassLoaderAware、BeanFactoryAware进行处理
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//应用后处理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//激活用户自定义的init方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//后处理器应用
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
五、注册DisposableBean
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
/** 单例模式下注册需要销毁的bean,
此方法中会处理实现DisposableBean的bean,
并且对所有的bean使用DestructionAwareBeanPostProcessors处理,
DisposableBean DestructionAwareBeanPostProcessors
*/
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
//自定义scope处理
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
spring不仅提供了初始化方法的扩展入口,同样也提供了销毁方法的扩展入口,
可以通过配置destroy-method方法实现,也可以注册后处理器
DestructionAwareBeanPostProcessor来统一处理bean的销毁。 随着这篇文章的结束,spring的bean的加载流程算是写完了,但这只是 冰山一角,每个方法里面调用的方法还可以继续解析,内容实在是太多了,但 是如果你能对bean的加载流程有个大概的了解,主要是那几个关键的方法能说 出来,一般面试的时候有这问题基本上都能答上了!
你可能感兴趣的:(spring,spring)
JAVA架构师需要掌握的常用架构模式有哪些?
猿享天开
Java开发从入门到精通 java 架构 开发语言
引言Java架构师必须掌握常用技术组合及其选型逻辑。技术组合的选择直接影响系统的可扩展性、性能和维护成本。以下是当前主流技术组合、选型原则及常用架构应用的详细说明:一、当前主流技术组合及其应用场景1.基础开发框架技术组合应用场景核心优势SpringBoot+MyBatis+MySQL中小型单体应用、快速迭代业务开发效率高、ORM轻量、数据库兼容性强SpringBoot+JPA+PostgreSQL
使用Spring Boot开发后端应用:在IntelliJ IDEA中的实践指南
风亦辰739
后端 spring boot java intellij-idea
一、什么是SpringBoot?SpringBoot是一个开源框架,用于简化Java应用的构建过程,尤其是Web应用。它是基于Spring框架的,提供了许多开箱即用的功能,极大地简化了Spring应用的配置和开发过程。SpringBoot让开发者无需关注繁琐的配置,可以专注于业务逻辑的实现。SpringBoot的优势:自动配置:SpringBoot根据项目的依赖自动配置相关功能,避免手动配置繁琐的
spring cloud gateway + nacos
没事偷着乐琅
微服务 微服务
pom.xml父类:org.springframework.bootspring-boot-starter-parent2.2.5.RELEASE2.2.5.RELEASE1.82.2.1.RELEASEorg.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimportcom.alibaba.clou
Nacos集成spring cloud gateway
舞娘展颜
gateway spring cloud alibaba
今天使用Nacos集成springcloudgateway,记录一下最开始我创建了一个module:cloud-gateway,并且在pom文件里配置这样(部分代码截取):com.exampledemo1.0.0然后启动的时候,就说已经使用了gateway,让去掉spring-boot-starter-web的依赖,因为我的父级pom里引入了spring-boot-starter-web。Spri
spring项目中读取类路径下文件的方式
初夏の猫
spring java sql
//1.Class.getResourceAsStream()InputStreaminputStream=LoadConfigUtil.class.getResourceAsStream("/mybatis-config.xml");//2.ClassPathResourcefontResource=newClassPathResource("fonts/msyh.ttf");InputStre
Springboot(五十)SpringBoot3集成sentinel并连接sentinel-dashboard
camellias_
spring boot sentinel 后端
对,你没看错,又是sentinel。我真是够了,而且,我觉得这应该不是最后一次,以后应该还会写到关于sentinel的学习记录。前边我们了解了sentinel如何使用。相对来讲还是比较简单的。之后学到自定义注解的时候,还自定义了一个sentinel注解来实现限流。用着相对来讲还是很方便的。但是呢,有一个小小的问题。官方推荐使用sentinel-dashboard,这玩意我一直没用明白。我得项目一直
Springboot(五十一)SpringBoot3整合Sentinel-nacos持久化策略
camellias_
spring boot sentinel java
上文中我记录了在Springboot项目中链接sentinel-dashboard使用限流规则的全过程。但是呢,有一个小小的问题,我重启了一下我本地的sentinel-dashboard服务,然后,我之前创建的所有的流控规则都没了……这……好像有点不合理啊,咱就不能找地儿存储一下?你这一重启就没了,我这可咋整。Sentinel的流控配置是可以存储在nacos配置中心中的。但是这个我好想没有在官方文
SpringBoot Jwt令牌的使用(黑马javaweb)
liuaiguo75
SpringBoot JAVA Idea spring boot 后端 java spring intellij-idea log4j mybatis
JWT概念JSONWebToken(JWT)是一种开放标准(RFC7519),它定义了一种紧凑和自包含的方式,用于作为JSON对象在各方之间安全地传输信息。这个信息可以被验证和信任,因为它是数字签名的。JWTs可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。JWT作用1、授权2、信息交换JWT示例代码1、SpringBoot中引入JWTio.jsonwebtoken
4、《Spring Boot 中的依赖管理》
wolf犭良
SpringBoot spring boot 后端 java
SpringBoot中的依赖管理摘要在SpringBoot项目开发的过程中,依赖管理是一项极为关键的工作,它直接关系到项目的稳定性、性能以及开发效率。本文将深入剖析Maven和Gradle这两种主流构建工具在SpringBoot项目中的依赖管理方式,详细介绍如何精准地引入依赖、巧妙地排除不必要的依赖,以及高效地处理版本冲突,帮助开发者牢牢掌控项目依赖,为项目的顺利推进筑牢根基。一、Maven在Sp
SpringBoot适配Sentinel
清扬叶
sentinel 后端
Sentinel介绍随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。Sentinel具有以下特征:丰富的应用场景:Sentinel承接了阿里巴巴近10年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。完备的实时监控:Senti
面试官:工作中,你有遇到过Spring事务失效的时候吗?
孙悟饭Z
spring java 数据库
在日常开发中,Spring事务管理是保证数据一致性的重要手段,但你是否遇到过明明加了@Transactional注解,事务却“神秘失效”的情况?这种问题不仅让新手抓狂,连老司机也偶尔翻车。本文总结了12种常见的Spring事务失效场景,结合代码示例和解决方案,帮你彻底避开这些坑!目录一、访问权限问题二、final或static方法三、方法内部调用1.使用AOP的AopContext2.注入自身四、
浅谈Java Spring Boot 框架分析和理解
微笑的曙光(StevenLi)
JAVA java spring boot 开发语言
SpringBoot是一个简化Spring开发的框架,它遵循“约定优于配置”的原则,通过内嵌的Tomcat、Jetty或Undertow等容器,使得开发者能够快速构建独立运行的、生产级别的基于Spring框架的应用程序。SpringBoot包含了大量的自动配置功能,可智能识别已存在的库并配置相应组件,从而减少手动配置的工作量。JavaSpringBoot是一个基于Spring框架的开源Java框架
springboot接入sentinel案例
ITzhongzi
spring boot sentinel 后端
版本控制springboot:3.3.2spring-cloud-starter-alibaba-sentinel:2023.0.3.2sentinel-dashboard:1.8.8项目源代码pom4.0.0org.springframework.bootspring-boot-starter-parent3.3.2com.dubbosentinel_demo20.0.1-SNAPSHOTsen
2.6 TestExecutionListener
不听话的小耳朵
springtest spring junit
TestExecutionListener`是SpringTest的核心扩展接口,允许开发者监听测试执行的生命周期事件,并插入自定义逻辑。通过实现此接口,可以干预测试的准备阶段、执行阶段和清理阶段,适用于监控、资源管理、日志记录等场景。1.TestExecutionListener核心方法接口定义了以下关键方法(均为默认方法,可按需重写):方法名触发时机典型用途beforeTestClass测试类
2.7 ContextLoader详解
不听话的小耳朵
springtest spring junit
ContextLoader详解与示例ContextLoader是SpringTest中用于加载ApplicationContext的核心接口,通过自定义ContextLoader,开发者可以完全控制Spring上下文的创建过程。它在以下场景中尤为重要:动态生成配置(如根据环境变量调整Bean定义)。集成外部工具(如Testcontainers动态获取数据库URL)。替代默认配置加载方式(如混合XM
SpringBoot服务器的采购上,服务器的数量和性能配置如何取舍【无标题】
陈老师还在写代码
SpringBoot100问 服务器 运维
在采购SpringBoot服务器时,需根据应用需求、预算和扩展性等因素综合考虑服务器的数量和性能配置。以下是一些关键点:1.应用需求分析用户量:用户量越大,需要的服务器性能和数量越多。请求频率:高并发请求需要更强的CPU和内存支持。数据处理:数据密集型应用需要更高的I/O性能和存储容量。响应时间:低延迟要求需要更快的CPU和更大的内存。2.性能配置CPU:高并发或复杂计算需要多核CPU。内存:内存
微服务常用技术栈
qq_29798761
微服务 架构 云原生
微服务项目通常涉及一系列技术栈,这些技术栈共同支持微服务的开发、部署、运行和治理。以下是一个典型的Java微服务项目可能用到的技术栈概览:1.构建与依赖管理Maven/Gradle:用于项目的构建和依赖管理。Maven和Gradle是Java项目中广泛使用的构建工具,它们能够自动化编译、打包、发布等过程,并管理项目所需的依赖库。2.微服务框架SpringBoot:用于快速构建独立的、生产级别的Sp
Spring事务注解配置
anyeoo
一天一点点 Spring事务注解配置
一,spring基于注解式的事务配置方法:@Transactional1.xml配置2.常用事物注解:2.1readOnly主要用于查询中:@Transactional(readOnly=true)用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。默认为读写事务2.2rollbackFor对于增删改查时的回滚,默认情况下checked except
2.3 事务控制注解
不听话的小耳朵
springtest junit spring java
事务控制注解详解SpringTest通过事务管理确保测试数据的隔离性,避免测试间的数据污染。以下是与事务控制相关的核心注解及其使用场景,结合代码示例说明其工作机制。1.@Transactional作用在测试方法或类上启用事务管理:所有数据库操作在事务内执行,默认在方法结束后回滚。隔离测试数据:确保每个测试方法的数据变更不会影响其他测试或持久化到数据库。使用场景测试数据库增删改操作(如save、up
Springboot 三层架构(Controller(控制层)、Dao(数据访问层)、Service(业务逻辑层))
残花月伴
spring boot 架构 后端
文章目录开发Stringboot一个功能的流程Springboot三层架构一、Controller(控制层)Controller(控制层)的作用1、如何创建Controller(控制层)2、在Controller(控制层)中如何调用Service(业务逻辑层)二、Service(业务逻辑层)Service(业务逻辑层)的作用:1、创建Service(业务逻辑层)2、为什么要去创建接口Service
使用gRPC代替SpringCloud微服务项目中的RPC框架OpenFeign
Gloic
spring cloud 微服务 rpc java
这是目录哦一.前言二.代码仓库三.关于gRPC和OpenFeign四.使用gRPC替代OpenFeign1.原OpenFeign客户端2.proto接口定义3.gRPC服务端4.gRPC客户端5.服务测试五.总结一.前言前段时间一直在忙着另一门课程的SpringCloud微服务项目,其中各个微服务之间使用的是OpenFeign进行服务之间的接口调用。这时候刚好在网络程序设计的课程中学习到了gRPC
SpringBoot依赖之PostgreSQL Driver集成
ahauedu
微服务架构设计 spring boot postgresql 后端
概念PostgreSQLDriverPostgreSQL是一个强大、开源的对象关系型数据库管理系统(ORDBMS),适用于大数量处理、复杂的应用程序、数据分析和BI、金融以及电子商务领域。PostgreSQLDriver依赖名称:PostgreSQLDriver功能描述:AJDBCandR2DBCdriverthatallowsJavaprogramstoconnecttoaPostgreSQLd
SpringBoot处理全局异常详解(全面详细+Gitee源码)
黄团团
SpringBoot Spring Java spring boot gitee 后端 java maven spring mybatis
前言:在日常的开发工作中,项目在运行过程中多多少少是避免不了报错的,对于报错信息肯定不可以把全部信息都抛给客户端去显示,这里就需要我们对常见的七种异常情况统一进行处理,让整个项目更加优雅。目录一、基本介绍二、项目整体结构图三、基础配置3.1、导入pom.xml依赖3.2、application.yml配置四、常用类封装4.1、HttpStatus状态码常量类4.2、AjaxResult统一封装返回
java 框架面试题-Spring Boot自定义配置与自动配置共存_自定义配置类 java
2401_85613964
java spring boot mybatis
SpringBoot是一个快速开发框架,可以简化Spring应用程序的开发,其中自定义配置是其中一个非常重要的特性。在SpringBoot中,自定义配置允许开发者以自己的方式来配置应用程序。自定义配置可以用于覆盖默认配置,也可以用于添加新的配置项。本文将详细介绍java框架面试题-SpringBoot自定义配置与自动配置共存,并提供Java代码案例。一.SpringBoot自定义配置的过程Spri
超硬核的java开源物联网智能家居系统
Github导航站
java github
今天小编推荐一套开源的软硬件系统,可用于二次开发和学习,快速搭建自己的物联网/智能家居系统。硬件工程师可以把自己的设备集成到系统;软件工程师可以使用项目中的设备熟悉软硬件交互。开源协议 使用MulanPSL-2.0开源许可协议链接地址 公众号【Github导航站】回复关键词【wum】获取git地址项目简介服务端 使用springboot、数据库mysql和redis、前端vue、移动端a
【基于SprintBoot+Mybatis+Mysql】电脑商城项目之获取省市区列表名称及收货地址列表展示
安清h
电脑商城项目 mybatis mysql 数据库 spring 后端
安清h:个人主页个人专栏:【Spring篇】【计算机网络】【Mybatis篇】作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。目录1.获取省市区列表-创建数据表2.获取省市区列表-实体类3.获取省市区列表-持久层✨3.1规划SQL语句✨3.2接口设计和抽象方法的实现4.获取省市区列表-业务层5.获取省市区列表-控制层✨5.1设计请求✨5.2处理请求6.获取省市区列表-
SpringBoot单体服务无感更新启动,动态检测端口号并动态更新
技匠而已
java
SpringBoot单体服务无感更新启动packagecom.basaltic.warn;importcn.hutool.core.io.IoUtil;importlombok.SneakyThrows;importorg.apache.commons.lang3.StringUtils;importorg.mybatis.spring.annotation.MapperScan;importor
java项目当中使用redis
ok!不当人
java项目的技术点 java redis 开发语言
分类数据一般情况下不会做过多的修改,因此可以将分类数据进行缓存,以提高页面的加载速度。1使用缓存先将首页接口获取一级分类数据缓存步骤:1、在service-product微服务中集成SpringDataRedis,如下所示:在service-product的pom.xml文件中添加如下依赖:org.springframework.bootspring-boot-starter-cacheorg.s
Spring MVC拦截器(Interceptor)
暮晓引流软件
面试 学习路线 阿里巴巴 mvc spring java 后端 c#
在系统中,经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中,即平时所说的“权限检测”及“日志记录”。当然不仅仅这些,所以需要一种机制,拦截用户的请求,在请求的前后添加处理逻辑。SpringMVC提供了Interceptor拦截器机制,用于请求的预处理和后处理。在开发一个网站时可能有这样的需求:某些页面只希望几个特定的用户浏览。对于这样的访问权限控制,应
Spring MVC中的拦截器和Servlet中的filter(过滤器)有什么区别?
猫猫爱敲代码
spring mvc servlet
一、作用范围过滤器(Filter):作用于整个Web应用程序,可以对所有的Servlet和JSP等资源进行过滤处理,是Servlet规范的一部分,独立于特定的框架。例如,一个用于编码转换的过滤器可以对所有请求和响应进行字符集的转换,无论请求是针对哪个具体的业务模块。拦截器(Interceptor):主要作用于SpringMVC框架中的请求处理过程,仅对SpringMVC管理的控制器方法的调用进行拦
web报表工具FineReport常见的数据集报错错误代码和解释
老A不折腾
web报表 finereport 代码 可视化工具
在使用finereport制作报表,若预览发生错误,很多朋友便手忙脚乱不知所措了,其实没什么,只要看懂报错代码和含义,可以很快的排除错误,这里我就分享一下finereport的数据集报错错误代码和解释,如果有说的不准确的地方,也请各位小伙伴纠正一下。
NS-war-remote=错误代码\:1117 压缩部署不支持远程设计
NS_LayerReport_MultiDs=错误代码
Java的WeakReference与WeakHashMap
bylijinnan
java 弱引用
首先看看 WeakReference
wiki 上 Weak reference 的一个例子:
public class ReferenceTest {
public static void main(String[] args) throws InterruptedException {
WeakReference r = new Wea
Linux——(hostname)主机名与ip的映射
eksliang
linux hostname
一、 什么是主机名
无论在局域网还是INTERNET上,每台主机都有一个IP地址,是为了区分此台主机和彼台主机,也就是说IP地址就是主机的门牌号。但IP地址不方便记忆,所以又有了域名。域名只是在公网(INtERNET)中存在,每个域名都对应一个IP地址,但一个IP地址可有对应多个域名。域名类型 linuxsir.org 这样的;
主机名是用于什么的呢?
答:在一个局域网中,每台机器都有一个主
oracle 常用技巧
18289753290
oracle常用技巧 ①复制表结构和数据 create table temp_clientloginUser as select distinct userid from tbusrtloginlog ②仅复制数据 如果表结构一样 insert into mytable select * &nb
使用c3p0数据库连接池时出现com.mchange.v2.resourcepool.TimeoutException
酷的飞上天空
exception
有一个线上环境使用的是c3p0数据库,为外部提供接口服务。最近访问压力增大后台tomcat的日志里面频繁出现
com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResou
IT系统分析师如何学习大数据
蓝儿唯美
大数据
我是一名从事大数据项目的IT系统分析师。在深入这个项目前需要了解些什么呢?学习大数据的最佳方法就是先从了解信息系统是如何工作着手,尤其是数据库和基础设施。同样在开始前还需要了解大数据工具,如Cloudera、Hadoop、Spark、Hive、Pig、Flume、Sqoop与Mesos。系 统分析师需要明白如何组织、管理和保护数据。在市面上有几十款数据管理产品可以用于管理数据。你的大数据数据库可能
spring学习——简介
a-john
spring
Spring是一个开源框架,是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只能由EJB完成的事情。然而Spring的用途不仅限于服务器端的开发,从简单性,可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。其主要特征是依赖注入、AOP、持久化、事务、SpringMVC以及Acegi Security
为了降低Java开发的复杂性,
自定义颜色的xml文件
aijuans
xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="white">#FFFFFF</color> <color name="black">#000000</color> &
运营到底是做什么的?
aoyouzi
运营到底是做什么的?
文章来源:夏叔叔(微信号:woshixiashushu),欢迎大家关注!很久没有动笔写点东西,近些日子,由于爱狗团产品上线,不断面试,经常会被问道一个问题。问:爱狗团的运营主要做什么?答:带着用户一起嗨。为什么是带着用户玩起来呢?究竟什么是运营?运营到底是做什么的?那么,我们先来回答一个更简单的问题——互联网公司对运营考核什么?以爱狗团为例,绝大部分的移动互联网公司,对运营部门的考核分为三块——用
js面向对象类和对象
百合不是茶
js 面向对象 函数创建类和对象
接触js已经有几个月了,但是对js的面向对象的一些概念根本就是模糊的,js是一种面向对象的语言 但又不像java一样有class,js不是严格的面向对象语言 ,js在java web开发的地位和java不相上下 ,其中web的数据的反馈现在主流的使用json,json的语法和js的类和属性的创建相似
下面介绍一些js的类和对象的创建的技术
一:类和对
web.xml之资源管理对象配置 resource-env-ref
bijian1013
java web.xml servlet
resource-env-ref元素来指定对管理对象的servlet引用的声明,该对象与servlet环境中的资源相关联
<resource-env-ref>
<resource-env-ref-name>资源名</resource-env-ref-name>
<resource-env-ref-type>查找资源时返回的资源类
Create a composite component with a custom namespace
sunjing
https://weblogs.java.net/blog/mriem/archive/2013/11/22/jsf-tip-45-create-composite-component-custom-namespace
When you developed a composite component the namespace you would be seeing would
【MongoDB学习笔记十二】Mongo副本集服务器角色之Arbiter
bit1129
mongodb
一、复本集为什么要加入Arbiter这个角色 回答这个问题,要从复本集的存活条件和Aribter服务器的特性两方面来说。 什么是Artiber? An arbiter does
not have a copy of data set and
cannot become a primary. Replica sets may have arbiters to add a
Javascript开发笔记
白糖_
JavaScript
获取iframe内的元素
通常我们使用window.frames["frameId"].document.getElementById("divId").innerHTML这样的形式来获取iframe内的元素,这种写法在IE、safari、chrome下都是通过的,唯独在fireforx下不通过。其实jquery的contents方法提供了对if
Web浏览器Chrome打开一段时间后,运行alert无效
bozch
Web chorme alert 无效
今天在开发的时候,突然间发现alert在chrome浏览器就没法弹出了,很是怪异。
试了试其他浏览器,发现都是没有问题的。
开始想以为是chorme浏览器有啥机制导致的,就开始尝试各种代码让alert出来。尝试结果是仍然没有显示出来。
这样开发的结果,如果客户在使用的时候没有提示,那会带来致命的体验。哎,没啥办法了 就关闭浏览器重启。
结果就好了,这也太怪异了。难道是cho
编程之美-高效地安排会议 图着色问题 贪心算法
bylijinnan
编程之美
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class GraphColoringProblem {
/**编程之美 高效地安排会议 图着色问题 贪心算法
* 假设要用很多个教室对一组
机器学习相关概念和开发工具
chenbowen00
算法 matlab 机器学习
基本概念:
机器学习(Machine Learning, ML)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。
它是人工智能的核心,是使计算机具有智能的根本途径,其应用遍及人工智能的各个领域,它主要使用归纳、综合而不是演绎。
开发工具
M
[宇宙经济学]关于在太空建立永久定居点的可能性
comsci
经济
大家都知道,地球上的房地产都比较昂贵,而且土地证经常会因为新的政府的意志而变幻文本格式........
所以,在地球议会尚不具有在太空行使法律和权力的力量之前,我们外太阳系统的友好联盟可以考虑在地月系的某些引力平衡点上面,修建规模较大的定居点
oracle 11g database control 证书错误
daizj
oracle 证书错误 oracle 11G 安装
oracle 11g database control 证书错误
win7 安装完oracle11后打开 Database control 后,会打开em管理页面,提示证书错误,点“继续浏览此网站”,还是会继续停留在证书错误页面
解决办法:
是 KB2661254 这个更新补丁引起的,它限制了 RSA 密钥位长度少于 1024 位的证书的使用。具体可以看微软官方公告:
Java I/O之用FilenameFilter实现根据文件扩展名删除文件
游其是你
FilenameFilter
在Java中,你可以通过实现FilenameFilter类并重写accept(File dir, String name) 方法实现文件过滤功能。
在这个例子中,我们向你展示在“c:\\folder”路径下列出所有“.txt”格式的文件并删除。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
C语言数组的简单以及一维数组的简单排序算法示例,二维数组简单示例
dcj3sjt126com
c array
# include <stdio.h>
int main(void)
{
int a[5] = {1, 2, 3, 4, 5};
//a 是数组的名字 5是表示数组元素的个数,并且这五个元素分别用a[0], a[1]...a[4]
int i;
for (i=0; i<5; ++i)
printf("%d\n",
PRIMARY, INDEX, UNIQUE 这3种是一类 PRIMARY 主键。 就是 唯一 且 不能为空。 INDEX 索引,普通的 UNIQUE 唯一索引
dcj3sjt126com
primary
PRIMARY, INDEX, UNIQUE 这3种是一类PRIMARY 主键。 就是 唯一 且 不能为空。INDEX 索引,普通的UNIQUE 唯一索引。 不允许有重复。FULLTEXT 是全文索引,用于在一篇文章中,检索文本信息的。举个例子来说,比如你在为某商场做一个会员卡的系统。这个系统有一个会员表有下列字段:会员编号 INT会员姓名
java集合辅助类 Collections、Arrays
shuizhaosi888
Collections Arrays HashCode
Arrays、Collections
1 )数组集合之间转换
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
a)Arrays.asL
Spring Security(10)——退出登录logout
234390216
logout Spring Security 退出登录 logout-url LogoutFilter
要实现退出登录的功能我们需要在http元素下定义logout元素,这样Spring Security将自动为我们添加用于处理退出登录的过滤器LogoutFilter到FilterChain。当我们指定了http元素的auto-config属性为true时logout定义是会自动配置的,此时我们默认退出登录的URL为“/j_spring_secu
透过源码学前端 之 Backbone 三 Model
逐行分析JS源代码
backbone 源码分析 js学习
Backbone 分析第三部分 Model
概述: Model 提供了数据存储,将数据以JSON的形式保存在 Model的 attributes里,
但重点功能在于其提供了一套功能强大,使用简单的存、取、删、改数据方法,并在不同的操作里加了相应的监听事件,
如每次修改添加里都会触发 change,这在据模型变动来修改视图时很常用,并且与collection建立了关联。
SpringMVC源码总结(七)mvc:annotation-driven中的HttpMessageConverter
乒乓狂魔
springMVC
这一篇文章主要介绍下HttpMessageConverter整个注册过程包含自定义的HttpMessageConverter,然后对一些HttpMessageConverter进行具体介绍。
HttpMessageConverter接口介绍:
public interface HttpMessageConverter<T> {
/**
* Indicate
分布式基础知识和算法理论
bluky999
算法 zookeeper 分布式 一致性哈希 paxos
分布式基础知识和算法理论
BY NODEXY@2014.8.12
本文永久链接:http://nodex.iteye.com/blog/2103218
在大数据的背景下,不管是做存储,做搜索,做数据分析,或者做产品或服务本身,面向互联网和移动互联网用户,已经不可避免地要面对分布式环境。笔者在此收录一些分布式相关的基础知识和算法理论介绍,在完善自我知识体系的同
Android Studio的.gitignore以及gitignore无效的解决
bell0901
android gitignore
github上.gitignore模板合集,里面有各种.gitignore : https://github.com/github/gitignore
自己用的Android Studio下项目的.gitignore文件,对github上的android.gitignore添加了
# OSX files //mac os下 .DS_Store
成为高级程序员的10个步骤
tomcat_oracle
编程
What
软件工程师的职业生涯要历经以下几个阶段:初级、中级,最后才是高级。这篇文章主要是讲如何通过 10 个步骤助你成为一名高级软件工程师。
Why
得到更多的报酬!因为你的薪水会随着你水平的提高而增加
提升你的职业生涯。成为了高级软件工程师之后,就可以朝着架构师、团队负责人、CTO 等职位前进
历经更大的挑战。随着你的成长,各种影响力也会提高。
mongdb在linux下的安装
xtuhcy
mongodb linux
一、查询linux版本号:
lsb_release -a
LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noa