• 第五周 Spring框架


    一、Spring框架设计

    Spring framework 6大模块

    1.1 Spring AOP

    AOP: 面向切面编程

    Spring 早期版本的核心功能,管理对象声明周期和对象装配

    为了实现管理和装配,一个自然的想法就是,加一个中间层代理(字节码增强)来实现所有对象的托管

    IoC:控制反转

    IoC是一个宽泛的概念,而DI(依赖注入)是其中的一种实现方式。

    从对象A直接引入和操作对象B,变成对象A只需要依赖一个接口IB,系统启动和装配阶段,把IB接口的实例对象注入到对象A,这样A就不需要依赖一个IB接口的具体实现。

    从而达到修改配置文件,就可以在运行时替换成注入IB接口的其他实现类的一个对象实例。

    思考:Spring怎么解决循环依赖?

    当实例A依赖B,实例B依赖A时。就构成了循环依赖。Spring解决的思路就是先构造一个"早期"对象,对象的属性还没填充,然后将这个早期对象注入容器。让B完成实例化,此时A就能获取到B的引用,完成了实例化。

    具体实现是通过Spring的三级缓存。

    什么类型的循环依赖Spring无法处理?

    答:双方都是构造函数注入或主bean对象(Spring启动中先加载的对象)使用构造函数注入。

    构造器注入和setter注入在创建bean时候的区别

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    	///隐藏无用代码
    		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);
    		}
    
    		// Preferred constructors for default construction?
    		ctors = mbd.getPreferredConstructors();
    		//如果ctors不为空,就是构造器注入
    		if (ctors != null) {
    			return
    			//需要去创建构造器里依赖的bean,此时还没实例化出对象来放入三级缓存
    			autowireConstructor(beanName, mbd, ctors, null);
    		}
    
    		//不是构造器注入,就可以实例化出一个bean来,并放入三级缓存里面了。
    		return instantiateBean(beanName, mbd);
    	}
    

    Spring AOP的实现方式:

    动态代理

    接口类型,默认使用JDK动态代理。非接口类型默认使用CGlib。

    如果接口类型想改为用CBlib动态代理:

    spring xml:

    <aop:aspectj-autoproxy  expose-proxy="true"    proxy-target-class="true"/>
    

    spring boot 配置文件:

    # 增加@EnableAspectJAutoProxy
    spring.aop.auto=true
    # 开启CGLIB代理
    spring.aop.proxy-target-class=true
    

    字节码增强

    1.2 Spring Bean

    Bean的加载过程:

    1. 创建对象
    2. 属性赋值
    3. 初始化
    4. 注销接口注册
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    			throws BeanCreationException {
    		// 1. 实例化bean
    		BeanWrapper instanceWrapper = null;
    		if (mbd.isSingleton()) {
    			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    		}
    		if (instanceWrapper == null) {
    			instanceWrapper = createBeanInstance(beanName, mbd, args);
    		}
    		final Object bean = instanceWrapper.getWrappedInstance();
    		Class<?> beanType = instanceWrapper.getWrappedClass();
    		if (beanType != NullBean.class) {
    			mbd.resolvedTargetType = beanType;
    		}
    
            /**
            省略部分代码
            **/
    
    		// Initialize the bean instance.
    		Object exposedObject = bean;
    		try {
    		    //2.属性赋值
    			populateBean(beanName, mbd, instanceWrapper);
    			//3.初始化
    			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);
    			}
    		}
    
    	/**
    	省略部分代码
    	**/
    
    		// 4.销毁的回调方法
    		try {
    			registerDisposableBeanIfNecessary(beanName, bean, mbd);
    		}
    		catch (BeanDefinitionValidationException ex) {
    			throw new BeanCreationException(
    					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    		}
    
    		return exposedObject;
    	}
    

    Bean的初始化过程:

    1. 检查Aware装配
    2. BeanPostProcessors前置处理
    3. init方法
    4. BeanPostProcessors后置处理
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            //1.检查Aware接口并设置相关依赖
    		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()) {
    		    //2.BeanPostProcessor前置处理
    			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    		}
    
    		try {
    		    //若有init方法,则执行
    		    //若实现了InitializingBean接口,则执行
    			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()) {
    		    //BeanPostProcessor后置方法处理
    			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    		}
    
    		return wrappedBean;
    	}
    
    书山有路勤为径,学海无涯苦作舟
  • 相关阅读:
    opencv之霍夫曼变换
    【Linux】【Jenkins】系统配置报反向代理设置有误问题的解决方案
    【Linux】【Selenium】安装Chrome和ChromeDriver的配置
    【Linux】【Jenkins】编译过程中遇到ERROR: Failed to parse POMs的解决方案
    【Linux】【Jenkins】代码编译和执行过程中的问题汇总
    【Linux】【Jenkins】邮件发送失败的问题javax.mail.MessagingException: Could not connect to SMTP host:
    【Linux】【Jenkins】配置过程中,立即构建时,maven找不到的问题解决方案
    【Linux】【GIt】Linux下安装和配置Git(转)
    【Linux命令】Linux下的tar压缩解压缩命令详解(转)
    【Linux】【Maven】Linux下安装和配置Maven
  • 原文地址:https://www.cnblogs.com/javammc/p/14873225.html
Copyright © 2020-2023  润新知