没长正的技术专栏 勤动手、多思考

Spring概述

2018-04-15

阅读:


1、Spring

基于servlet 自己设计spring主要流程

2021-11-21_自己实现Spring

1.0 Spring 核心组件

BeanFactory产生一个新的实例可以实现单例模式
BeanWrapper提供统一的get及set方法
ApplicationContext:提供框架的实现包括BeanFactory的所有功能

Spring 框架中的核心组件只有三个:Core、Context 和 Beans。它们构建起了整个 Spring 的骨骼架构。

1.0.1 初始化

protected void onRefresh(ApplicationContext context) {
    this.initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    this.initMultipartResolver(context);
    this.initLocaleResolver(context);
    this.initThemeResolver(context);
    this.initHandlerMappings(context);
    this.initHandlerAdapters(context);
    this.initHandlerExceptionResolvers(context);
    this.initRequestToViewNameTranslator(context);
    this.initViewResolvers(context);
    this.initFlashMapManager(context);
}

1.0.2 ApplicationContext 与 BeanFactory关系

2021-12-06_ApplicationContext接口及父类

1.1 Spring概述

​ Context是入口

定位 用的 Reader 结尾的

加载 BeanDefinition保存类信息,包括OOP关系

注册 Factroy、Context 就是把用户所定义的Bean放到IOC容器中(Map)

2、IOC实现原理

围绕Bean来展开

BeanFactory来创建的

reader load

do开头的都是具体干活

ClassPathXmlApplicationContext 通过main方法启动

DispatchServlet

FileSystem

Plugin

Lisenter

parseBeanDefinitions 方法实际是解析xml,把xml中的内容变成BeanDefinition (类信息)

参考图示:

2.1 XML对Bean初始化

2.1.1 默认无参构造函数

  • SimpleInstantiationStrategy 使用默认无参构造方法创建Bean对象

    //使用初始化策略实例化 Bean 对象
    @Override
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        // Don't override the class with CGLIB if no overrides. 
        //如果 Bean 定义中没有方法覆盖,则就不需要 CGLIB 父类类的方法 
        if (!bd.hasMethodOverrides()) {
             Constructor<?> constructorToUse;
             synchronized (bd.constructorArgumentLock) {
        //获取对象的构造方法或工厂方法
        constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; //如果没有构造方法且没有工厂方法
        if (constructorToUse == null) {
            //使用 JDK 的反射机制,判断要实例化的 Bean 是否是接口 
            final Class<?> clazz = bd.getBeanClass();
            if (clazz.isInterface()) {
                throw new BeanInstantiationException(clazz, "Specified class is an interface"); }
                try {
                        if (System.getSecurityManager() != null) {
                        //这里是一个匿名内置类,使用反射机制获取 Bean 的构造方法 
                            constructorToUse = AccessController.doPrivileged(
                                              (PrivilegedExceptionAction<Constructor<?>>) () -> clazz.getDeclaredConstructor());
                        }
                        else {
                                        constructorToUse = clazz.getDeclaredConstructor();
                             }
                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Throwable ex) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
                } 
              }
            //使用 BeanUtils 实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化
            return BeanUtils.instantiateClass(constructorToUse); 
            }
            else {
            // Must generate CGLIB subclass.
            //使用 CGLIB 来实例化对象
            return instantiateWithMethodInjection(bd, beanName, owner);
        } 
    }
    

通过上面的代码分析,我们看到了如果 Bean没有方法被覆盖了,则使用 JDK 的反射机制进行实例化,否 则,使用 CGLIB 进行实例化。

instantiateWithMethodInjection 方 法 调 用 SimpleInstantiationStrategy 的 子 类 CglibSubclassingInstantiationStrategy 使用 CGLIB 来进行初始化,其源码如下:

//使用 CGLIB 进行 Bean 对象实例化
public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) {
    //创建代理子类
    Class<?> subclass = createEnhancedSubclass(this.beanDefinition); Object instance;
    if (ctor == null) {
        instance = BeanUtils.instantiateClass(subclass); }
        else { 
            try {
                   Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
                   instance = enhancedSubclassConstructor.newInstance(args);
                }
                catch (Exception ex) {
                throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
                "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
                } 
        }
        Factory factory = (Factory) instance; factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
                   new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
                   new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
             return instance;
            }
        private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) { //CGLIB 中的类
        Enhancer enhancer = new Enhancer();
        //将 Bean 本身作为其基类 enhancer.setSuperclass(beanDefinition.getBeanClass()); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        if (this.owner instanceof ConfigurableBeanFactory) {
        ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader(); enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
        }
        enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition)); enhancer.setCallbackTypes(CALLBACK_TYPES);
        //使用 CGLIB 的 createClass 方法生成实例对象
        return enhancer.createClass();
    } 
}

CGLIB 是一个常用的字节码生成器的类库,它提供了一系列 API 实现 java字节码的生成和转换功能。 我们在学习 JDK 的动态代理时都知道,JDK 的动态代理只能针对接口,如果一个类没有实现任何接口, 要对其进行动态代理只能使用 CGLIB。

2.1.2 AnnotationConfigApplicationContext 对注解 Bean 初始化

​ Spring 中 , 管 理 注 解 Bean 定 义 的 容 器 有 两 个 : AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext。这两个类是专门处理 Spring 注解方式配置的容器,直 接依赖于注解作为容器配置信息来源的 IOC 容器。 AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本,两者的用法以及对注解的处理方式几乎没有什 么差别。

现在来看看 AnnotationConfigApplicationContext 的源码:

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
	//保存一个读取注解的 Bean 定义读取器,并将其设置到容器中 
    private final AnnotatedBeanDefinitionReader reader;
	//保存一个扫描指定类路径中注解 Bean 定义的扫描器,并将其设置到容器中 
    private final ClassPathBeanDefinitionScanner scanner;
	//默认构造函数,初始化一个空容器,容器不包含任何 Bean 信息,需要在稍后通过调用其 register() //方法注册配置类,并调用 refresh()方法刷新容器,触发容器对注解 Bean 的载入、解析和注册过程 
    public AnnotationConfigApplicationContext() {
         this.reader = new AnnotatedBeanDefinitionReader(this);
         this.scanner = new ClassPathBeanDefinitionScanner(this);
       }
   public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
         super(beanFactory);
         this.reader = new AnnotatedBeanDefinitionReader(this);
         this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
	//最常用的构造函数,通过将涉及到的配置类传递给该构造函数,以实现将相应配置类中的 Bean 自动注册到容器中 
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
         this();
         register(annotatedClasses);
         refresh();
    }
	//该构造函数会自动扫描以给定的包及其子包下的所有类,并自动识别所有的 Spring Bean,将其注册到容器中 
    public AnnotationConfigApplicationContext(String... basePackages) {
         this();
         scan(basePackages);
         refresh();
    }
   @Override
   public void setEnvironment(ConfigurableEnvironment environment) {
     super.setEnvironment(environment);
     this.reader.setEnvironment(environment);
        this.scanner.setEnvironment(environment);
   }
	//为容器的注解 Bean 读取器和注解 Bean 扫描器设置 Bean 名称产生器
	public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
         this.reader.setBeanNameGenerator(beanNameGenerator);
         this.scanner.setBeanNameGenerator(beanNameGenerator);
         getBeanFactory().registerSingleton(
    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
    }
	//为容器的注解 Bean 读取器和注解 Bean 扫描器设置作用范围元信息解析器
	public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
     this.reader.setScopeMetadataResolver(scopeMetadataResolver);
     this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
   }
	//为容器注册一个要被处理的注解 Bean,新注册的 Bean,必须手动调用容器的 //refresh()方法刷新容器,触发容器对新注册的 Bean 的处理
	public void register(Class<?>... annotatedClasses) {
    	Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
         this.reader.register(annotatedClasses);
       }
    //扫描指定包路径及其子包下的注解类,为了使新添加的类被处理,必须手动调用 //refresh()方法刷新容器
    public void scan(String... basePackages) {
    	Assert.notEmpty(basePackages, "At least one base package must be specified");
         this.scanner.scan(basePackages);
   	}
... 

}

通过对 AnnotationConfigApplicationContext 的源码分析,我们了解到 Spring 对注解的处理分为 两种方式: (1).直接将注解 Bean 注册到容器中:

​ 可以在初始化容器时注册;也可以在容器创建之后手动调用注册方法向容器注册,然后通过手动刷新容 器,使得容器对注册的注解 Bean 进行处理。

(2).通过扫描指定的包及其子包下的所有类:

​ 在初始化注解容器时指定要自动扫描的路径,如果容器创建以后向给定路径动态添加了注解 Bean,则 需要手动调用容器扫描的方法,然后手动刷新容器,使得容器对所注册的 Bean 进行处理。

3、SpringAOP

面向切面编程 -> 代理(JDKProxy、CgLib) 解耦

4、编程思想与总结

Spring 思想 应用场景(特点) 一句话归纳
AOP Aspect Oriented Programming(面向切面编程) 找出多个类中有一定规律的代码,开发时拆开,运行时再合并。 面向切面编程,即面向规则编程。 解耦,专人做专事。
OOP Object Oriented Programming(面向对象编程) 归纳总结生活中一切事物。 封装、继承、多态
BOP Bean Oriented Programming(面向Bean编程) 面向Bean(图通的Java类)程序设计 一切从Bean开始
IOC Inversion Of Control(控制反转) 转交控制权
DI/DL Dependency Injection(依赖注入)或者Dependancy Lookup(依赖查找) 依赖注入、依赖查找,Spring不仅保存自己创建的对象,而且保存对象与对象之间的关系。注入即赋值,主要三种发共识构造方法、set方法、直接赋值 先理清关系再赋值

参考: GP-Tom老师学习源码


欢迎拍砖,多多交流,转载请注明出处:[没长正的技术专栏](http://blog.meizhangzheng.com) 如涉及侵权问题,请发送邮件到xsj34567@163.com,如情况属实本人将会尽快删除。


上一篇 Spring学习方法

Comments

Content