Spring原理及源码简单版解剖.

Spring的优势:

1. 解耦合, 简化开发

2. AOP编程的支持

3. 声明式事务的支持

4. 方便程序的测试

5. 方便集成各种优秀框架

Spring的核心结构:

web模块, 数据访问与集成,Test模块,

AOP模块, Core Container模块

核心思想:

错误认知:IOC容器(是一个map而已; 准确来说, map是ioc容器的一个成员,叫做单例池

singletonObjects, 容器是一组组件和过程的集合, 包括BeanFactory, 单例池, BeanPostProcessor等之间的协助流程)

什么是IOC?Inversion of Control 是技术思想

问题:创建A对象, 而A对象依赖与B对象, 这时候如果B对象的实例类发生了改变, 那么A对象的代码也需要改变, 显然, A和B耦合在一起!

Control : 指对象的创建(实例化, 管理) 的权利

Inversion : 把控制权交由Spring.

我们丧失了⼀个权利(创建、管理对象的权利) , 得到了⼀个福利(不⽤考虑对象的创建、管理等⼀系列 事情)

IOC与DI的区别? Dependancy Injection 依赖注入

IOC和DI只是理解的角度不同而已,IOC指站在对象的角度, 把控制权交由了IOC容器, 而DI则是站在容器的角度, 把容器中一个实例对象注入到其他对象。

什么是AOP?

在大多数情况中我们都是采用 OOP(继承, 封装, 多态), 垂直继承体系
但是某种情况下, 我们是解决不了的, 当我们需要给一段业务代码增加处理前和处理后的逻辑, 并且大量的业务都存在这样的代码增加是, 怎么解决这个问题了? 
其实AOP思想就是 横切逻辑, 我们横向切开处理, 比如我们实现一个代理类, 需要实现前后处理的就通过代理类来处理, 代理类中, 进行横向添加重复代码。中间业务根据代理对象而来。

静态代理: 需要为每个业务创建一个代理类。

动态代理:

JDK

public interface RentingHouse{

    public void rentHouse ;
} 

public class RentingHouseImpl implements RentingHouse {

    public void rentHouse() {
        System.out.pringln("我要租房子") ;
    }
} 

public class JdkProxy {

    public static void main(String args[]) {
        // 委托对象
       RentingHouse rentHouse =  new RentingHouseImpl () ;
       // 获取代理对象
       Object proxy = Proxy.newProxyInstance(
          rentHouse.getClass().getClassLoader,
          rentHouse.getClass().getInterfaces(),
          new InvocationHanler() {
                public Object invoke(Object proxy, Method method, Object[] args) {
                   System.out.pringln("代理前") ;
                   Object result = method.invoke(proxy, args)
                   System.out.pringln("代理后") ;
                   return result ;
                }

        }); 


    }


}

CGLIB:

// cglib代理需要添加依赖

public class CglibProxy {

    public static void main(String args[]) {
        // 委托对象
       RentingHouse rentHouse =  new RentingHouseImpl () ;
       // 获取代理对象
       Object proxy = Enhancer.create(
          rentHouse.getClass(),
           // 需要一个拦截器
          new MethodInterceptor() {
                public Object invoke(Object proxy, Method method, Object[] args,         
                           MethodProxy methodProxy) {
                   System.out.pringln("代理前") ;
                   Object result = method.invoke(proxy, args)
                   System.out.pringln("代理后") ;
                   return result ;
                }

        }); 


    }

区别: JDK委托对象必须实现接口, CGLIB没有这个规定!

SpringBean的生命周期:

1. 实例化bean:

根据配置情况调用,Bean构造方法或工厂方法实例化对象

2. 设置属性值

利用依赖注入完成bean的所有属性值得配置注入

3. 调用BeanNameAware的setBeanName()

如果实现了这个接口, 则调用setBeanName

4. 调用   BeanFactoryAware的setBeanFactory() ;

如果实现了这个接口, 则调用setBeanFactory

5. 调用ApplicationAware的setApplicaitonContext()

如果实现了这个接口, 则调用setApplicaitonContext, 当前得ApplicaitonContext实例引用

6. 调用BeanPostProcessor()

如果BeanPostProcessor与Bean关联, 则Spring将调用该接口得预初始方法, postProcessBeforeInitialzation() 对Bean进行加工, Spring得AOP就是利用它实现得

7. 调用InitializingBean的afterPropertiesSet()

如果 Bean 实现了 InitializingBean 接⼝,则 Spring 将调⽤ afterPropertiesSet() ⽅法
8. 调用定制得初始化方法 init-method
如果在配置⽂件中通过 init-method 属性指定了初始化⽅法,则调⽤该初始化⽅法。

9. 调用BeanPostProcessor()后初始化方法

如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调⽤该接⼝的初始化⽅法postProcessAfterInitialization()。 此时,Bean 已经可以被应⽤系统使⽤了。
10. 如果在 <bean> 中指定了该 Bean 的作⽤范围为 scope="singleton",则将该 Bean 放⼊ Spring IoC 的缓存池中, 将触发 Spring 对该 Bean 的⽣命周期管理;如果在 <bean> 中指定了该 Bean 的作⽤范围为 scope="prototype",则将该 Bean 交给调⽤者

11. 如果 Bean 实现了 DisposableBean 接⼝,则 Spring 会调⽤ destory() ⽅法将 Spring 中的 Bean 销毁; 如果在配置⽂件中通过 destory-method 属性指定了 Bean 的销毁⽅法,则 Spring 将调⽤该⽅法对 Bean 进⾏销毁。

注意: Spring Bean 提供了细致全⾯的⽣命周期过程,通过实现特定的接⼝或 <bean> 的属性设置,都可以对 Bean 的⽣命周期过程产⽣影响。
虽然可以随意配置 <bean> 的属性,但是建议不要过多地使⽤ Bean 实现接⼝,因为这样会导致代码和 Spring 的聚合过于紧密

BeanDefifinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为⼀个 JavaBean, 这个JavaBean 就是 BeanDefifinition

BeanDefifinition存储信息 类名 scope 属性 构造函数参数列表 依赖的 bean 是否是单例类 是否是懒加载 等,
其实就是 Bean 的定义信息存储到这个 BeanDefifinition 相应的属性中,后⾯对 Bean 的操作就直接对 BeanDefifinition 进⾏
例如拿到这个 BeanDefifinition 后,可以 根据⾥⾯的类名、构造函数、构造函数参数,使⽤反射进⾏对象创建

 BeanFactory和 FactoryBean : 

1. BeanFactory是容器的顶级接口, 定义了容器的基础行为, 负责生产和管理Bean工厂,它下面还要高级容器ApplicationContext比它更为丰富。
      BeanFactory的继承体系设计非常优雅, 没有把所有的容器操作都放在了BeanFactory这个顶级父类里面, 而是采用了分层思想: 指功能被打散, 想要用那个功能, 再去实现某个接口即可。
       
2. Spring中的Bean有俩种, 一种是普通的, 一种是工厂Bean, 我们可以通过 FacotryBean实现自定义Bean的创建流程
Bean的创建三种方式: 静态方法, 实例化方法, FactoryBean. 作用类似, FactoryBean使用较多, 尤其在Spring框架的一些组件中使用,还要其他框架与spring整合时使用。 

FactoryBean案列:

@Data
public class Company {

    private String name;
    private String address;
    private int scale;

    @Override
    public String toString() {
        return "Company{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", scale=" + scale +
                '}';
    }

}


public class CompanyFactoryBean implements FactoryBean<Company> {

    private String companyInfo ; // 公司名称,地址,规模

    public void setCompanyInfo(String companyInfo) {
        this.companyInfo = companyInfo ;
    }
    @Override
    @Bean
    public Company getObject() throws Exception {

        // 模拟创建复杂对象Company
        Company company = new Company();
        String[] split = companyInfo.split(",");
        company.setName(split[0]);
        company.setAddress(split[1]);
        company.setScale(Integer.parseInt(split[2]));

        return company;
    }

    @Override
    public Class<?> getObjectType() {
        return Company.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}


 public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new         ClassPathXmlApplicationContext("application.xml");
        Object bean = context.getBean("companyBean");
        System.out.println("bean: " + bean);

        Object bean1 = context.getBean("&companyBean");
        System.out.println(bean1);
    }

<!--    <bean id="companyBean" class="com.leiyu.factory.CompanyFactoryBean">-->
<!--        <property name="companyInfo" value="拉勾,中关村,500"/>-->
<!--    </bean>-->

后置处理器:

Spring提供了两种后置处理器:分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使⽤上是有所区别的。

工厂初始化:BeanFactory ---> Bean对象

在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置一些事情, 比如我们可以获取到BeanDefifinition对象, 以⼿动修改bean标签中所定义的属性值。

注意:调⽤ BeanFactoryPostProcessor ⽅法时,这时候bean还没有实例化,此时 bean 刚被解析成  BeanDefifinition对象
public class FactoryBeanDemo implements BeanFactoryPostProcessor {

    /**
     *  BeanFactory级别的处理,是针对整个Bean的⼯⼚进⾏处理
     *  典型应⽤:PropertyPlaceholderConfigurer
     * @param configurableListableBeanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("xxx");
        beanDefinition.setBeanClassName("xxx");
        
    }
}
Bean 对象实例化(并不是 Bean 的整个⽣命周期完成)之后可以使⽤ BeanPostProcessor 进⾏后置处 理做⼀些事情
注意:处理是发⽣在Spring容器的实例化和依赖注⼊之后。
/**
 *  该接⼝提供了两个⽅法,分别在Bean的初始化⽅法前和初始化⽅法后执⾏,
 */
public class SpringBeanDemo implements BeanPostProcessor {


    /**
     *  默认对所有Bean进行处理
     * @param bean  每个bean的实例
     * @param beanName 每个bean的name 或 id 值, 我们可以通过这个参数来判断具体的bean
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

注意:对象不⼀定是SpringBean,⽽SpringBean⼀定是个对象

IOC容器初始化读取流程:

1. 根据SpringBean生命周期得时机点:根据栈得信息

        构造器,初始化执行方法都经过, bean后置处理器得before()/after(): AbstractApplicationContext#refresh#finishBeanFactoryInitialization

        Bean工厂后置处理器初始化,方法执行:

AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors

        BeanPostProcessor后置处理器初始化:

AbstractApplicationContext#refresh#RegisterBeanPostProcessors

2. 代码时机锁定到了refresh()  IOC容器创建得核心方法, spring提供给我们,一个容器启动后,还可以刷新这个容器。

        a.进去后首先有一个Synchtonized对象锁和close()互斥, 保证在刷新得时候不能close()

        b.


// 刷新前的预处理:设置启动时机, 开启活跃状态, 验证环境信息里一些必要的属性
protected void prepareRefresh() {
        // 启动日期和活动标志
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true); 
        if (this.logger.isDebugEnabled()) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Refreshing " + this);
            } else {
                this.logger.debug("Refreshing " + this.getDisplayName());
            }
        }
        
        // 设计模式中模板方法模式--也叫做钩子方法
        this.initPropertySources();  // 可拓展, 给子类自定义容器, 可以在这个方法内说明
        this.getEnvironment().validateRequiredProperties(); // 验证环境信息里一些必要的属性
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);   
        } else {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        this.earlyApplicationEvents = new LinkedHashSet();
    }

        c. 创建工厂, 把xml中Bean对象封装成BeanDefinition

// 比较关键的一步
 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

        d. Beanfactory的预准备工作(比如context的类加载信息)

this.prepareBeanFactory(beanFactory);

        e. 刚才是前置, 现在是BeanFactory预准备工作完成后, 进行后置处理工作

this.postProcessBeanFactory(beanFactory);

// 这里也是没有进行实现的, 模板方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

        f. 实例化实现了BeanFactoryPostProcessor接口的Bean, 要开始调用接口方法了

this.invokeBeanFactoryPostProcessors(beanFactory);

        g.到这里, bean还没有被实例化, 指注册Bean的后置处理器, 在创建Bean前后执行

this.registerBeanPostProcessors(beanFactory);

        h. 初始化Message组件(做国际化功能, 消息绑定, 解析)

        i. 初始化事件派发器

        j. onRefresh()也是让子类从写, 在容器刷新时可以自定义逻辑, 如创建Tomcat

        k.registerListeners() 注册应用监听器, 就是实现了ApplicatioListeners的bean要注册进来

        l. 初始化剩下的非懒加载单例bean, 创建实例bean, 填充属性, 初始化方法的调用(

afterPropertiesSet(),  init-method() ) 调用BeanPostProcessor对实例Bean进行后置处理

 this.finishBeanFactoryInitialization(beanFactory);

       m.   this.finishRefresh();  

BeanFactory创建的子流程:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        this.refreshBeanFactory();
        return this.getBeanFactory();
 }

 protected final void refreshBeanFactory() throws BeansException {

        // 判断是否已经有了 BeanFactory
        if (this.hasBeanFactory()) { // 内部加了同步关键字
            // 销毁
            this.destroyBeans();
             // 关闭
            this.closeBeanFactory();
        }

        try {
            // 实例化 DefaultListableBeanFactory 
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            // 设置序列化ID
            beanFactory.setSerializationId(this.getId());
             //自定义bean工厂的一些属性(id相同是否覆盖,是否循序循环依赖)
            this.customizeBeanFactory(beanFactory);
            // 加载应用中的Definition
            this.loadBeanDefinitions(beanFactory);
            // 赋值给当前的factory
            this.beanFactory = beanFactory;
        } catch (IOException var2) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
        }
    }

BeanDefinition 的注册

// 从创建工厂中进入 // 加载应用中的Definition this.loadBeanDefinitions(beanFactory);
// 来到org.springframework.context.support.AbstractRefreshableConfigApplicationContext

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        
        // 给指定的BeanFactory创建一个XmlBeanDefinitionReader读取器, 解析xml对象
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        // 给XmlBeanDefinitionReader设置context上下文中的环境属性
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // 提供子类实现提供的一些自定义初始化策略  构子方法
        this.initBeanDefinitionReader(beanDefinitionReader);
        // 真正去加载beanDefinitions
        this.loadBeanDefinitions(beanDefinitionReader);
    }

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        
        // 从Resource 资源对象加载beanDefinitions
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        // 
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }

    }

  // 如果有多个配置文件循环读取
   //org.springframework.beans.factory.support.AbstractBeanDefinitionReader
 public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int count = 0;
        String[] var3 = locations;
        int var4 = locations.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String location = var3[var5];
            count += this.loadBeanDefinitions(location);
        }

        return count;
    }

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        // 获取上下文的资源加载器
        ResourceLoader resourceLoader = this.getResourceLoader();

        // 判断资源加载器是否为ResourcePatternResolver xml  url等不同类型统一接口
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int count;
            if (resourceLoader instanceof ResourcePatternResolver) {
                try {
                    
                    // 统一加载转换为Resource资源对象
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);

                    // 加载资源中配置的BeanDefinition对象, 返回数量
                    count = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Collections.addAll(actualResources, resources);
                    }
                    return count;
                } 
        }
    }

    // 刚才的for是循环xml文件, 这个for 是循环抽象后的Resource资源文件
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        Resource[] var3 = resources;
        int var4 = resources.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Resource resource = var3[var5];
            count += this.loadBeanDefinitions((Resource)resource);
        }

        return count;
    }

 Bean创建流程

//  1. this.finishBeanFactoryInitialization(beanFactory);
//  2. public void preInstantiateSingletons() throws BeansException 
//  3. protected <T> T doGetBean

Spring IOC 循环依赖 :  解决循环依赖靠的是三级缓存

一级:单例池 二级: early  三级: singletonFactorys

理论说明:BeanA  和 BeanB 循环依赖

1.  当A实例化后里面暴漏在三级缓存, 当时B也不列外

2. 这时候B创建时发现依赖于A, 即使用尚未成型的A。

3.  升级放入二级缓存, (这个时候可以做很多事情)

4. B这个时候已经创建完成放入一级缓存

5. A这个时候就可以使用一级缓存的成型的B

Spring AOP 应用

AOP 本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、⽇志代 码、事务控制代码、性能监控代码。
Joinpoint( 接点) : 它指的是那些可以⽤于把增强代码加⼊到业务主线中的点,   在⽅法执⾏的前后通过动态代理技术加⼊增强的代码。  (⽅法类型的连接点)
Pointcut( ⼊点): 它指的是那些已经把增强代码加⼊到业务主线进来之后的连接点。
Advice( / 增强):   前置通知 后置通知 异常通知 最终通知 环绕通
Target( ⽬标 对象): 它指的是代理的⽬标对象。即被代理对象。
Proxy( 代理) : 它指的是⼀个类被 AOP 织⼊增强后,产⽣的代理类。即代理对象。
Weaving( ⼊) :    它指的是把增强应⽤到⽬标对象来创建新的代理对象的过程。 spring 采⽤动态代 理织⼊,⽽  AspectJ 采⽤编译期织⼊和类装载期织⼊。
Aspect( ⾯) :  它指定是增强的代码所关注的⽅⾯,把这些相关的增强代码定义到⼀个类中,这 个类就是切⾯类。
Aspect 切⾯ = 切⼊点 +增强  =  切⼊点(锁定⽅法) + ⽅位点(锁定⽅法中的特殊时机) + 横切逻辑
Spring 实现 AOP 思想使⽤的是动态代理技术, 可以根据代理对象是否有接口自动选择
 <bean id="logUtil" class="com.leiyu.main.LogUtil"></bean>
<!--开始aop的配置-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect id="logAspect" ref="logUtil">
            <aop:pointcut id="pt1" expression="execution(* com.leiyu.factory.CompanyFactoryBean.getObject(*))"/>
            <!--配置前置通知-->
            <aop:before method="beforeMethod" pointcut-ref="pt1"></aop:before>
        </aop:aspect>
    </aop:config>

注解模式:

@Component
@Aspect
class LogUtil {
    

    @Pointcut("execution(* com.lagou.service.impl.*.*(..))")
     public void pointcut(){}

    @Before("pointcut()")
     public void beforePrintLog(JoinPoint jp){
         Object[] args = jp.getArgs();
         System.out.println("前置通知:beforePrintLog,参数是:"+
           Arrays.toString(args));
 }
    
}

<!--开启spring对注解aop的⽀持-->
<aop:aspectj-autoproxy/>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值