Spring 知识点整理

     Spring作为开源的框架目前正被互联网行业广泛的使用,在我们在面试的过程中也经常会被问到。这篇博客记录了我在学习spring的IOC容器中遇到的一些琐碎的知识点,并对相关文档进行参考,把它记录下来,巩固和学习,如有错误,欢迎指正。我们经常会被问 什么是spring? 其实很多人都认为spring就是IOC和AOP,其实不然,spring是产品,里面包含很多技术,包括springcloud,springdata,springfremwork等等,IOC和AOP只是spring中核心技术的一部分。

目录

一、spring IOC容器

1、基本内容

1.1、什么是Spring IOC?

1.2、什么是DI(依赖注入)

1.3、为什么要使用spring IOC

1.4、spring有几种编程风格

1.5、Spring依赖注入方式有哪些

1.6、spring的自动装配模式有哪些

1.7、自动装配方式有哪些

扫描二维码关注公众号,回复: 8790942 查看本文章

1.8、自动装配的优缺点

1.9、ApplicationContext 创建并初始化spring容器

2、spring的beans

2.1、单例和原型

2.2、Singleton的bean中引用了一个Prototype的bean的时候会出现Prototype失效的情况

2.3、spring生命周期回调有哪几种方式,执行顺序是什么

2.4、当spring容器完成初始化之后,想执行某个方法,怎么做

2.5、在spring源码中生命周期初始化回调方法initializeBean做了哪些事情

3、spring注解的一些知识点

3.1、@Autowired注解和自动注入模式的关系

3.2、@Autowired和@Resource的区别

3.3、属性是如何注入的

二、spring中的AOP

三、spring中的重要类

FactoryBean

beanDefintion

四、spring中的扩展点

4.1、BeanPostProcessor

4.2、AutowiredAnnotationBeanPostProcessor

4.3、CommonAnnotationBeanPostProcessor

4.4、BeanFactoryPostProcessor

4.5、BeanDefinitionRegistryPostProcessor

4.6、ConfigurationClassPostProcessor

五、解读spring源码中的知识点

5.1、jdk动态代理实现原理

5.2、cglib代理如何实现

5.3、spring中在哪些地方用到了动态代理

5.4、spring源码中使用了哪些设计模式

5.5、spring中有哪些不能被代理的bean

5.6、FactoryBean和普通bean的区别?

5.7、如何把自己自定义的对象放到spring容器中

5.8、为什么Appconfig类是通过register(Appconfig.class);手动put到map当中呢?为什么不是扫描出来的呢?

5.9、为什么spring当中默认支持循环依赖?或者spring在哪里体现了默认支持循环依赖?

5.10、spring事务不生效有哪些原因

5.11、推断构造方法


一、spring IOC容器

1、基本内容

1.1、什么是Spring IOC?

     首先IOC(Inversion of Control)就是控制反转,官网说法是,IOC也被称为DI(依赖注入)。官网截图如下:

Spring IOC是指:将对象的实例化反转给spring容器,在传统的开发模式中,当我们创建一个对象时,需要new或者newInstance等直接或者间接的方式调用构造方法创建这个对象,这样对象的实例化控制权是由应用程序控制的。而反转就是将这种权利反转给spring容器,spring容器通过工厂模式为程序员创建了所需的对象,程序员无需创建对象(只需要提供对象的类型即可),直接调用spring容器提供的对象就行了,这就是控制反转。

1.2、什么是DI(依赖注入)

依赖注入(DI)是指:spring 使用 java 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程,就是依赖注入的思想。

1.3、为什么要使用spring IOC

第一:对象的实例化不是一件简单的事情,比如对象的关系比较复杂,依赖关系往往需要程序员去维护,这是一件非常头疼的事;

第二:解耦,由容器去维护具体的对象;

第三:托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分过程交给容器,应用程序则无需去关心类是如何完成代理的。

1.4、spring有几种编程风格

     官网上说spring在1.0 使用xml配置方式,在2.5引入了注解 annotation(注解)配置方式,在3.0引入了javaconfig配置方式。官网说明如下:

1.5、Spring依赖注入方式有哪些

      查看spring官方文档可知,注入方式有两种:

      1、Constructor-based Dependency Injection(构造方法注入)

      官方文档详见:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-constructor-injection

      2、Setter-based Dependency Injection(基于setter的注入方式)

      官方文档详见:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection

1.6、spring的自动装配模式有哪些

Spring的自动注入模型有四种:

no(默认)无自动装配。

byName:按照名称进行装配,<bean id="dao" name="dao" class="">   spring会根据name的名字进行装配(默认 id 和name相同),在类中,name的值要与set方法一致  :例如: name="zlu"    setter的方法应该为setZlu()  才能进行自动装配。

byType:按类型进行装配,spring会找 依赖的属性的接口或者父类下的实现类或者子类,进行注入,例如: private IndexDao dao;    spring会找实现了IndexDao接口的类进行注入。

Constructor类似于byType,但适用于构造函数参数。如果容器中没有一个构造函数参数类型的bean,则会引发致命错误,使用Constructor的方式,系统会推断构造方法,选择参数最多的构造方法,解析构造方法的参数(每个参数表示一个依赖项)去找bean。

1.7、自动装配方式有哪些

  有两种方式:在XML中有如下两种配置方式,按照setter的名字对应:

spring也提供了相应的api:

1.8、自动装配的优缺点

    优点:

   (1) 自动装配可以显著减少指定属性或构造函数参数的需要(减少依赖的注入的配置)

   (2) 当对象发生改变会自动更新配置。例如,如果需要向类添加依赖项,在容器中添加bean即可。

详细信息查看官方文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-autowire

    缺点:(但是这些缺点对于我来说不能算作缺点)

(1) property和constructor-arg设置中的显式依赖项能够覆盖自动装配(xml中配置的依赖能够使自动装配无效)。

(2)自动装配不如显式注入精确,无法明确记录Spring管理对象之间的关系。

(3) 可能无法为可能从Spring容器生成文档的工具提供连线信息。

(4)容器中的多个bean定义可以匹配setter方法或构造函数参数指定的类型以进行自动装配。对于数组,集合或Map实例,这不

一定是个问题。但是,对于期望单个值的依赖关系,这种模糊性不是任意解决的。如果没有可用的唯一bean定义,则抛出异常。

详细信息查看官方文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-autowired-exceptions

1.9、ApplicationContext 创建并初始化spring容器

ApplicationContext可以通过ClassPathXmlApplicationContext和AnnotationConfigApplicationContext创建并初始化容器。

代码如图:

//java config的方式
ApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);
//xml的方式
ApplicationContext context1 = new ClassPathXmlApplicationContext("spring.xml");

2、spring的beans

2.1、单例和原型

  官方参考文档;https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scope。我们用的最多的是: singleton:单例(默认),每次获取的hashcode相同; prototype:原型:每次获取的hashcode不同。单例的对象在spring创建和初始化的时候实例化的,spring会将对象放入到一个单例池中(源码中的singletonMap中)缓存起来,在使用时直接去map中获取即可,原型的对象是在getBean的时候实例化的。

2.2、Singleton的bean中引用了一个Prototype的bean的时候会出现Prototype失效的情况

原因是:假设A是单例的,B是原型的,A依赖了B,那么虽然被依赖的对象B是prototype的,但是A对象是singleton的,在运行的过程中 这个A对象只是实例化了一次,因此只有一次机会设置B,每次需要时,容器不能为A提供B的实例。

解决方案:就是放弃控制反转,每次调用B时,为B创建新的实例。

     1、在service类中新写一个方法,在方法上添加@Lookup  ,代码如下:

@Service
@Scope(value = "singleton")
public class IndexServiceImpl  {

    @Autowired
    private IndexDao dao;

    public void query(){
        System.out.println("service:"+this.hashCode());
        getDao().test();
    }

    @Lookup()
    public IndexDao getDao() {
        return null;
    }
}

 (注意:Spring提供了一个名为@Lookup的注解,这是一个作用在方法上的注解,被其标注的方法会被重写,然后根据其返回值的类型,容器调用BeanFactory的getBean()方法来返回一个bean。源码中  在实例化的过程中,会将加了@LookUp的方法放到MethodOverrides set中,beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);生成实例策略时会判断,如果set里面有值,则return instantiateWithMethodInjection(bd, beanName, owner);进入这个方法,cglib代理)

     2、实现接口ApplicationContextAware

     官方参考:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-method-injection

代码如下:

@Service
@Scope(value = "singleton")
public class IndexServiceImpl1 implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    public void query(){
        System.out.println("service:"+this.hashCode());
        ((IndexDao)applicationContext.getBean("indexDaoImpl")).test();
    }
}

2.3、spring生命周期回调有哪几种方式,执行顺序是什么

  参考文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-lifecycle

Spring中实现生命周期的回调有三种方式,一种是注解@PostConstruct和 @PreDestroy,一种是实现接口,InitializingBean,重写afterPropertiesSet()方法,实现接口DisposableBean,重写destroy()方法,还有一种是通过spring提供的xml里面配置一个default-init-method="init"或者      default-destroy-method=“destory”标签,指明方法。这三种方式都能实现spring生命周期的回调,但是他们有一个执行顺序,是注解最先,接口第二,xml指定是第三,为什么呢?因为spring处理生命周期回调是基于spring的生命周期来的,有源码得知,spring先通过一个后置处理器(InitDestroyAnnotationBeanPostProcessor)拿到这个注解解析执行,然后再执行invokeInitMethods方法,在invokeInitMethods方法里面依次执行接口方法(判断bean是否实现了InitializingBean接口)和xml方法

2.4、当spring容器完成初始化之后,想执行某个方法,怎么做

采用生命周期回调。(spring源码)在bean属性注入之后(就是bean被初始化之后立马执行bean的初始化回调方法) 进行生命周期回调。

2.5、在spring源码中生命周期初始化回调方法initializeBean做了哪些事情

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//执行加了@PostContrustot 注解的方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
			//执行bean的生命周期回调的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()) {
			//执行后置处理器的after方法 在这里 进行aop形成代理
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}

3、spring注解的一些知识点

3.1、@Autowired注解和自动注入模式的关系

@Autowired(是spring包中提供的注解)与自动注入模型没有关系,它属于手动装配,先根据类型(注意 这个类型不是自动注入模型中的byType模型)找,找不到再根据名称(注意 这个名称不是自动注入模型中的byName模型)找,找到了则注入,没有找到则异常,与byType和byName无关

可以通过代码进行验证:

程序中通过获取自动装配模型 得到结果为0,咋源码中得知 0代表 不采用自动装配。源码说明如下:

3.2、@Autowired和@Resource的区别

(1)提供者不一样  @Autowired是spring包中提供的注解,@Resource是jdk中提供的注解;

(2)解析类不一样 @Autowired是由后置处理器AutowiredAnnotationBeanPostProcessor解析,@Resource是由后置处理器CommonAnnotationBeanPostProcessor解析

(3)功能不一样 @Autowired是先根据类型找,在根据name找,@Resource是先根据name找,找不到再根据type找。

3.3、属性是如何注入的

首先属性注入在spring源码中是在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean方法中执行的。

源码如下:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	   //注释无关代码
       PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		/**
		 * 自动注入模型,当自动注入模式为byType或者byName时进入这个判断,
		 * 加了@Autowire注解的 不进入这个判断,证明了@Autowire不属于自动注入模型
		 */
		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();
			if (hasInstAwareBpps) {
				//根据不同的BeanPostProcessor(策略),完成不同注解的解析,进行属性注入,在循环依赖
				//的时候,进行属性注入还会getBean一下
				/**
				 * 循环所有的BeanPostProcessors后置处理器,判断是否是InstantiationAwareBeanPostProcessor的实现类,
				 * AutowiredAnnotationBeanPostProcessor后置处理器和CommonAnnotationBeanPostProcessor后置处理器
				 * 都实现了这个接口。所以如果属性加了@Autowired注解和@Resource注解,则进入这个判断
				 */
				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 (pvs != null) {
			// 注释 5.5 解析参数,如果是引用对象,将会进行提前加载
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

@Autowired属性注入一般有以下几种情况:

// (1)  OrderDao是一个具体类
@Autowired
private OrderDao orderDao;

// (2)  I是一个接口 有多个实现类,orderDao是其中一个
@Autowired
private I orderDao;

// (3)  List集合封装接口I
@Autowired
private List<I> list;

 接下来通过断点的方式进入postProcessPropertyValues方法:

@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
		//findAutowiringMetadata()方法这里获取注入元数据信息
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
            //真正的注入方法
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

再次进入findAutowiringMetadata方法,再从这个方法进入buildAutowiringMetadata方法,在这个方法中找打所有加了Autowired注解并且符合要求的field和method放在list集合中:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				//查找这个对象中有没有加了@Autowired注解的属性
				AnnotationAttributes ann = findAutowiredAnnotation(field);
				if (ann != null) {
					//如果存在  这个属性不能是Static类型的,因为Autowired注解不支持
					//static类型的属性
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isWarnEnabled()) {
							logger.warn("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					//获取这个autowired注解里的Required 是什么状态
					boolean required = determineRequiredStatus(ann);
					//将这个加了Autowired注解的属性加入list集合中
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				//获取这个对象中 所有的方法上面的@Autowired注解
				AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					//如果有注解,首先不能是static类型的
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isWarnEnabled()) {
							logger.warn("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					//Autowired注解只能用于带有参数的方法
					if (method.getParameterCount() == 0) {
						if (logger.isWarnEnabled()) {
							logger.warn("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					//获取这个autowired注解里的Required 是什么状态
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					//将这个加了Autowired注解的方法加入list集合中
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});
			//将上面两个currElements的数据放入一个集合中
			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);
		//封装
		return new InjectionMetadata(clazz, elements);
	}

 接下来进入metadata.inject方法进行真正的属性注入:

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		//获取对象中加了@Autowired注解的元数据集合
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			//循环遍历
			for (InjectedElement element : elementsToIterate) {
				if (logger.isDebugEnabled()) {
					logger.debug("Processing injected element of bean '" + beanName + "': " + element);
				}
				//注入
				element.inject(target, beanName, pvs);
			}
		}
	}

通过断点进入element.inject方法:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		 Field field = (Field) this.member;
		Object value;
		if (this.cached) {
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}else {
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			try {
                  //获取符合条件的属性集合
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			synchronized (this) {
				if (!this.cached) {
					//如果加了autowired注解的field的required=true,则进入
					if (value != null || this.required) {
						this.cachedFieldValue = desc;
						//注册依赖的bean
						registerDependentBeans(beanName, autowiredBeanNames);
						/**
						 * 如果只有一个bean的名字,那么获取这个beanName判断
						 * 在bean的工厂中是否存在,如果存在并且跟这个file的类型匹配,
						 * 说明spring工厂中存在这个类,可以进行注入
						 */
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
						if (beanFactory.containsBean(autowiredBeanName) &&
									beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									this.cachedFieldValue = new ShortcutDependencyDescriptor(
										desc, autowiredBeanName, field.getType());
								}
							}
						}else {
							this.cachedFieldValue = null;
						}
						this.cached = true;
					}
				}
			}
			if (value != null) {
				//重要
				ReflectionUtils.makeAccessible(field);
				//真正的注入就是通过java的field.set方法将属性注入进来
				field.set(bean, value);
			}
		}
	}

 进入doResolveDependency方法能够获取符合条件的属性集合:

@Nullable
	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}
			//获取属性类型
			Class<?> type = descriptor.getDependencyType();
			//获取注解中的value的名字,不设置的话一般为空
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}
			/**
			 * 如果field类型是数组,list或者map的话,就去找符合条件的所有bean
			 * 封装到set集合中,直接返回
			 */
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}
			//如果filed不是上面几种类型,则说明注入的bean只有一个,直接去匹配
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			if (matchingBeans.size() > 1) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(type, matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

	@Nullable
	private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
		//获取加了autowired注解的属性类型
		Class<?> type = descriptor.getDependencyType();
		/**
		 * 如果是数组类型的,则进入这个判断,找到所有符合条件的bean,放到set集合中
		 */
		if (type.isArray()) {
			Class<?> componentType = type.getComponentType();
			ResolvableType resolvableType = descriptor.getResolvableType();
			Class<?> resolvedArrayType = resolvableType.resolve();
			if (resolvedArrayType != null && resolvedArrayType != type) {
				type = resolvedArrayType;
				componentType = resolvableType.getComponentType().resolve();
			}
			if (componentType == null) {
				return null;
			}
			//查找符合条件的bean
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof Object[]) {
				Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		/**
		 * 如果是集合类型的,则进入下面这个判断,根据集合中的对象类型查找符合条件的bean
		 * 放到set集合中
		 */
		else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
			Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
			if (elementType == null) {
				return null;
			}
			//根据集合中的对象类型查找符合条件的bean,如果对象类型为接口,则去找所有的接口实现类
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof List) {
				((List<?>) result).sort(adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		/**
		 * 如果是map类型的,则进入下面这个判断,根据集合中的对象类型查找符合条件的bean
		 * 放到set集合中
		 */
		else if (Map.class == type) {
			ResolvableType mapType = descriptor.getResolvableType().asMap();
			Class<?> keyType = mapType.resolveGeneric(0);
			if (String.class != keyType) {
				return null;
			}
			Class<?> valueType = mapType.resolveGeneric(1);
			if (valueType == null) {
				return null;
			}
			//根据集合中的对象类型查找符合条件的bean,根据key和value去匹配spring容器中的bean
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			return matchingBeans;
		}
		else {
			return null;
		}
	}

 总结:

首先判断注解是@Autowired 还是@Resource,如果是前者,则使用AutowiredAnnotationBeanPostProcessor后置初期器处理,如果是后者,则使用CommonAnnotationBeanPostProcessor后置处理器处理,用前者举例,首先去获取注入的属性的类型,将其beanmane存放在set集合中,判断如果set的长度如果为1,则用beanName去容器中匹配,返回true,通过field.set注入,例如:

@Autowired

       private OrderDao orderDao;

如果是接口的形式:则找到所有实现了这个接口的类,放到map<beanName,Class>中,如果map的长度大于1,说明根据类型找会找出多个,有冲突,那么就 去循环这个map,找出与这个与依赖的 这个名称palyDao有没有相同beanName,如果有,则取出,实例化,通过field.set注入。如果找不到,则报错,注意被注入的属性不能是static的,否则不会生效,例如:

@Autowired

private I palyDao;

如果是List类型,spring会拿到这个field的类型List判断是不是Array,在判断是不是Collection并且类型是接口,如果是则获取这个list的类型com.zlu.aspect.I I,拿到之后将这个接口的所有实现类用Map<String, Object>存放起来,用Set<String>将所有的map.keySet 存放起来,然后将这写类全部注入进来:field.set(bean, value),例如:

@Autowired

private List<I> list;

二、spring中的AOP

三、spring中的重要类

  • FactoryBean

  • beanDefintion

四、spring中的扩展点

spring容器中有一些扩展点在再spring创建bean的生命周期中扮演着重要的角色。spring中有两个重要的扩展点的接口,分别是BeanPostProcessor和BeanFactoryPostProcessor。他们下面有很多实现类,承担着不同的任务。

4.1、BeanPostProcessor

BeanPostProcessor是Spring扩展点之一,BeanPostProcessor是一个接口,程序员可以通过实现它,插手bean的实例化过程,在bean创建前后,在bean被spring管理之前,做一些事情。在源码中使用了很多BeanPostProcessor的实现类做一些事情,例如使用AutowiredAnnotationBeanPostProcessor解析@Autowired注解,在实例化之后做属性注入;使用CommonAnnotationBeanPostProcessor解析其他如@Resource 注解,在实例化之后做属性注入;使AbstractAutoProxyCreator完成aop功能,以及完成动态代理功能,解析@PostConstruct注解等等。

我们自己编写一个类实现BeanPostProcessor来实现简单的jdk代理,简单代码如下:

@Component
public class MyPostProsser implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		//如果是AOP的话,相当于返回的是代理
		Object cc = Proxy.newProxyInstance(MyPostProsser.class.getClassLoader(),
				bean.getClass().getInterfaces(), new MyInvocationHandler(bean));
		return cc;
	}
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

4.2、AutowiredAnnotationBeanPostProcessor

 AutowiredAnnotationBeanPostProcessor实现了BeanPostProcessor,在spring进行属性注入的过程中,完成了对@Autowired注解的解析,找到加了@Autowired的field和method,放到集合中,等待进行注入。

4.3、CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor实现了BeanPostProcessor,在spring进行属性注入的过程中,完成了对@Resources注解的解析,找到加了@Resources的field和method,放到集合中,等待进行注入。

4.4、BeanFactoryPostProcessor

程序员可以通过实现它,修改应用程序上下文的内部bean工厂、读取bean的定义,覆盖或添加属性,例如:

//@Component
public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		//获取bd
		GenericBeanDefinition aa = (GenericBeanDefinition) beanFactory.getBeanDefinition("zluService1");
		//设置自动注入模型的类型
		aa.setAutowireMode(2);
		System.out.println(aa.getAutowireMode());
		//设置bean对应的类
		aa.setBeanClass(ZluService.class);

	}
}

4.5、BeanDefinitionRegistryPostProcessor

4.6、ConfigurationClassPostProcessor

五、解读spring源码中的知识点

5.1、jdk动态代理实现原理

JDK动态代理是通过方法newProxyInstance实现的,具体方法如下:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

参数说明:

ClassLoader loader:动态加载一个类,类加载器定义代理类,获取类加载器后,可以通过这个加载器,在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要。

Class<?>[] interfaces:接口数组 ,代理类要实现的接口列表,以便于生成的代理类可以具有代理类接口中的所有方法。

InvocationHandler h:在这里面,代理类要实现接口,并重写里面的方法,在invoke方法里面实现具体逻辑。

InvocationHandler里面有一个invoke方法实现具体代理逻辑,如下:

public Object invoke(Object proxy, Method method, Object[] args)   

参数说明:

 Object proxy:生成的代理对象,在这里不是特别的理解这个对象,但是个人认为是已经在内存中生成的proxy对象。

Method method:被代理的对象中被代理的方法的一个抽象,method.invoke方法能够实现被代理的类的真正逻辑。

Object[] args:被代理方法中的参数。这里因为参数个数不定,所以用一个对象数组来表示。

5.2、cglib代理如何实现

实际上,会生成一个代理类,这个代理类继承了目标对象,重写了目标对象里面的方法,在方法的前后执行代理逻辑。

例如,我们写一个目标类:

//目标类
public class E {
   public void cglibMethod(){
      System.out.println("target ");
   }
}

然后再写一个执行代理逻辑的类:

/**
 * 真正实现代理逻辑的类,必须实现MethodInterceptor接口,重写intercept方法
 * 在intercept方法中编写代理逻辑
 */
public class MyMethodInterceptor implements MethodInterceptor {
   @Override
   public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
      System.out.println("cglib");
      //执行目标方法
       methodProxy.invokeSuper(o,objects);
      return null;
   }
}

 然后编写测试程序:

//测试
public class Test {
   public static void main(String[] args) throws IllegalAccessException, InstantiationException {
      Enhancer enhancer = new Enhancer();
      //增强父类 cglib是基于继承的
      enhancer.setSuperclass(E.class);
      enhancer.setUseFactory(false);
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      //拦截器 对目标对象进行拦截 重要
      enhancer.setCallback(new MyMethodInterceptor());
      E subclass = (E) enhancer.create();
      subclass.cglibMethod();
   }
}

最终Cglib产生的代理类类似如下 :

/**
 * 假设这是cglib的代理类(这是生成的)
 */
public class XXXCglib extends E{
   MyMethodInterceptor my;
   @Override
   public void cglibMethod() {
      my.intercept();
   }
}

5.3、spring中在哪些地方用到了动态代理

5.4、spring源码中使用了哪些设计模式

  • 简单的工厂模式,又叫做静态工厂方法(StaticFactory Method)模式。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。

spring中的BeanFactory就是简单工厂模式的体现,Spring使用工厂模式可以通过 BeanFactory或 ApplicationContext创建 bean 对象,比如ApplicationContext的实现类AnnotationConfigApplicationContext、ClassPathXmlApplicationContext通过javaconfig或者xml创建和初始化spring容器。

  •        单例的设计模式,通过使用注解@Scope(value="singleton")实现单例模式,在spring容器中默认使用单例模式,在spring源码中会解析加了这个注解的bean,在创建bean后,将它保存到singletonObjects(ConcurrentHashMap)的单例池中,在下次使用时,直接获取即可。
  •        代理设计模式,spring中使用到了JDK动态代理和cglib代理。

对于AppConfig这个配置类,加了@Configuration和不加这个注解,都能创建和初始化spring容器,但是却有一些差别。在spring处理bean的工厂的后置处理器的时候,对于上了@Configuration的配置类设置full标志,把没有带上@Configuration,但是带上了@Component @ComponentScan @Import @ImportResource等注解的配置类设置为lite标志。spring会对加了full标志的配置类进行cglib代理,如果配置类里面加了@Bean注解的方法多次new同一个对象,只能创建一次,反之创建多次。

总结:保证单例,对方法进行调用的时候,spring会记录一下当前创建bean的方法,如果在方法内部还调用了另外的方法,spring会将两个方法进行比对,当前创建bean的方法和当前执行的方法 是否一样,如果一样,则调用父类去创建bean(superinovke()),如果不一样,则会调用自己的逻辑去创建bean,就是getBean)。

Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理。

  •        策略模式,spring源码中多次使用到了这个模式,例如:在spring完成属性注入的时候,去遍历所有的bean的后置处理器BeanPostProcessor,根据不同的策略完成不同的注解解析。  BeanPostProcessor的后置处理器的实现类分别执行不同的策略,CommonAnnotationBeanPostProcessor 主要处理@Resource注解的,AutowiredAnnotationBeanPostProcessor主要处理@Autowired注解 等等。

5.5、spring中有哪些不能被代理的bean

5.6、FactoryBean和BeanFactory的区别?

BeanFactory 是Bean 工厂是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从正真的应用代码中分离。常用的 BeanFactory 实现有 DefaultListableBeanFactory 、 XmlBeanFactory 、 ApplicationContext 等。
XMLBeanFactory,最常用的就是 org.springframework.beans.factory.xml.XmlBeanFactory ,它根据 XML 文件中的定义加载 beans。该容器从 XML 文件读取配置元数据并用它去创建一个完全配置的系统或应用。

FactoryBean是spring中提供的一个接口,可以通过实现它,重写getObject方法来返回真正的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

5.7、如何把自己自定义的对象放到spring容器中

  • 实现FactoryBean ,重写getObject方法,使用FactoryBean主要是因为项目总引入了第三方jar包,或者扩展第三方而言的。
  • 注解@Bean,是程序员为了进行零配置这么写。
  • 注册一个bean,这种写法比较鸡肋,例如:

5.8、为什么Appconfig类是通过register(Appconfig.class);手动put到map当中呢?为什么不是扫描出来的呢?

因为他无法扫描自己,一般类是spring通过解析Appconfig上的@ComponentScan注解然后被扫描到,所以无法扫描自己,

因此在源码中,当我们启动spring时通过下面这个方法,才会将AppConfig注册到spring中,才能解析这个配置类上面的注解,从而扫描

ApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);

5.9、为什么spring当中默认支持循环依赖?或者spring在哪里体现了默认支持循环依赖?

具体解析流程参见博客:https://blog.csdn.net/java_lyvee/article/details/101793774

总结:首先spring在单例的(非构造方法注入的情况下)情况下是默认支持循环引用的;在不做任何配置的情况下,两个bean相互依赖是能初始化成功的;spring源码中在创建bean的时候先创建这个bean的对象,创建对象完成之后通过判断容器对象的allowCircularReferences属性决定是否允许缓存这个临时对象,如果能被缓存成功则通过缓存提前暴露这个临时对象来完成循环依赖;而这个属性默认为true,所以说spring默认支持循环依赖的,但是这个属性spring提供了api让程序员来修改,所以spring也提供了关闭循环引用的功能;再就是spring完成这个临时对象的生命周期的过程中当执行到注入属性或者自动装配的周期时候会通过getSingleton方法去得到需要注入的b对象;而b对象这个时候肯定不存在故而会创建b对象创建b对象成功后继续b对象的生命周期,当执行到b对象的自动注入周期时候会要求注入a对象;调用getSingleton;从map缓存中得到a的临时对象(因为这个时候a在set集合中;a在进入第二个getSingleton方法的时候会将a添加到一个set集合中,标志a正在创建,这个set集合非常有用),而且获取的时候也会判断是否允许循环引用,但是判断的这个值是通过参数传进来的,也就是spring内部调用的,spring源码当中写死了为true,故而如果需要扩展spring、或者对spring二次开发的的时候程序员可以自定义这个值来实现自己的功能;不管放到缓存还是从缓存中取出这个临时都需要判断;而这两次判断spring源码当中都是默认为true;这里也能再次说明spring默认是支持循环引用的;

然后面试中可以在说说两次调用getSingleton的意义,正在创建的那个set集合有什么用;最后在说说你在看spring循环引用的时候得出的aop实例化过程的新发现;就比较完美了。

两次调用getSingleton的意义?

第一次调用getSingleton,是从单例池中获取这个bean,第一次一般单例池中不存在,第二次调用getSingleton,bean真正实例化和初始化就是在这里完成的。

正在创建的那个set集合有什么用?

第一次创建a,a在进入第二个getSingleton方法之后,会在方法中将a添加到一个set集合中,标志a正在创建,这个标志非常有用,以为当对象b第一次创建对象时,进行属性注入的时候,会注入a对象,就会getBean(a),然后进入第一个getSingleton中 ,这个时候就会判断当singletonObject单例池中不存在这个a对象,并且a正在创建这个标志成立,才会去获取a的bean,如何获取的?首先从看第三个缓存map中有没有,没有的话就去第二个singletonFactory工厂缓存中找,找到了就放到第三个缓存中,移除第二个工厂缓存。

spring循环引用的时候得出的aop实例化过程的新发现?

在创建bean的过程中,先会进行属性注入,注入后会通过调用initializeBean方法初始化bean,这个方法中通过applyBeanPostProcessorsBeforeInitialization会先处理spring生命周期的回调,先执行加了@PostContrustot 注解的方法,再执行xml配置的init方法,最后执行applyBeanPostProcessorsAfterInitialization方法进行aop代理(解析切面,创建代理)

如何关闭循环依赖呢?

可已通过两种方式,第一种,使用spring提供的api:

public class ZluTest {
	public static void main(String[] args) {
		//初始化容器
		AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext();
		DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
		//关闭循环依赖
		beanFactory.setAllowCircularReferences(false);
		context.register(AppConfig.class);
		context.refresh();
}

第二种,更改源码,重写getSingleton(beanName,false)方法,将里面的allowEarlyReference置为false,能够关闭循环依赖,spring默认是开启的,源码如下: 

public Object getSingleton(String beanName) {
		//重点,一定要记住这里传的是一个true,表示允许循环依赖
		return getSingleton(beanName, true);
	}

或者也可以通过下面这种方式:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    //关闭循环依赖
    setAllowCircularReferences(false);
    register(annotatedClasses);
    refresh();
}

5.10、spring事务不生效有哪些原因

5.11、推断构造方法

发布了6 篇原创文章 · 获赞 5 · 访问量 1003

猜你喜欢

转载自blog.csdn.net/qq_28203555/article/details/83339867