factory_method 工厂创建bean实例

依赖倒置

A. 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。 B. 抽象不能依赖于具象,具象依赖于抽象。

  • IOC控制反转:说的是创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件控制,侧重于原理。
  • DI依赖注入:说的是创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。

配置

  • @Component:用于说明一个类是一个spring容器管理的类。@Controller, @Service, @Repository是- @Component的细化,这三个注解比@Component带有更多的语义,它们分别对应了控制层、服务层、持久层的类。@Component注解或者其子类(找个本质上还是@Component)标记的类,认为这些类是bean, 并且把这些bean对应的beanDefinition放到容器中进行管理。BeanDefinition是对bean的描述,里边存有bean的名称,Class等基本信息。
  • @Service:用于服务层的IServiceImpl类文件,
  • @Controller:标识类是一个控制器。在servlet中使用。
  • @Repository:写在类上,标识该类作为一个spring bean由spring进行管理,即可将其注入到其它类中去。给持久层的类定义一个名字,让Spring根据这个名字关联到这个类。
  • @RequestMapping:可以注解在@Controller标注的类上,也可以注解@Controller标注类的方法,指定请求到方法的映射关系。为了进行更精确匹配,使用value指定路径,method指定请求方法,params指定请求参数。Header指定请求头。返回值的类型有约束。
  • @ResponseBody:表示这个方法将直接响应HTTP内容。
  • @Autowired:写在字段上,或写在setter方法上,用来装配bean。这里的bean就是前面几个标注定义的。相当于new了一个实现类,不需要实现setter方法。
  • @Resource:作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面 @Resource 默认按 byName 自动注入罢了。
  • @PathVariable:用于访问URI template变量。

对应xml脚本的配置,此时会探测base-package包下的注释的bean到spring容器中,当然这里的fitler也可以不要:

<context:component-scan base-package="com.zxr.manager"> 
        <context:include-filter type="regex" expression=".*DaoImpl"/> 
        <context:include-filter type="regex" expression=".*ServiceImpl"/> 
    </context:component-scan> 

在bean中配置的property,需要类中有对应的set实现方法,或者标签。

ClassPathXmlApplicationContext

指定classpath方式,具体使用如下,

  • “classpath:” 用户加载类路径(包括jar包)中的一个且仅一个资源,对于对个匹配的也值返回一个。
  • “classpath*:” 可以匹配对个资源,并返回。 classpath后面的路径中可以采用ant模式匹配,其中,
  • ?:匹配一个字符。
  • *:匹配零个或者多个字符,如cn/*/config.xml匹配cn/sub/config.xml,但是不匹配cn/config.xml.
  • **:匹配路径中的零个或多个目录,如cn/**/config.xml匹配cn/sub/config.xml,也匹配cn/config.xml。 实际使用时,发现该匹配方式会有遗漏,建议使用全路径指定吧。

spring bean 作用域

singleton(默认),prototype,reqeust,session,global-session。

bean启动流程:

构造函数,setter,preprocessbeforeInit,init-method,postPrecessAfterInit,destroy-method。 自动装配:no,byname,bytype,构造函数,autodetect。

  • 1,ApplicationContext接口,没有任何方法,只是继承了BeanFactory接口,暗示ApplicationContext与BeanFactory都是获取Bean的地方。
  • 2,AbstractApplicationContext抽象类,首先,它的构造函数接收入参BeanFactory,所以说ApplicationContext内部具有一个BeanFactory。类似于一种装饰器模式,但不是装饰器模式,类似于代理模式,但也不是代理模式。fresh方法分为三个步骤:
    1. loadBeanDefinitions,这个是一个模板方法,需要子类实现,它的作用就是从某一个地方读取BeanDefinition,然后写入到ApplicationContext自己的BeanFactory里面,这就是ApplicationContext与BeanFactory之间的联系,也就是ApplicationContext还负责了读取定义。
    2. registerBeanPostProcessors,这个就是在BeanFactory里面找到BeanPostProcessor,然后将他们放到BeanFactory的beanPostProcessors容器里面,方便BeanFactory初始化使用。
    3. onRefresh初始化一遍所有的bean。
      ClassPathXmlApplicationContext实现了loadBeanDefinitions的方法,将xml文件和BeanFactory结合在一起。
    4. 资源加载到BeanFactory,BeanFactory中PostProcessor的bean注册到BeanFactory;
    5. 遍历BeanFactory中所有bean的定义:根据BeanDefinition,创建实例(工厂方法,容器自动装配,无参构造函数),加入到BeanDefintion中;(单例,lazy_init为false)
  • 3,执行BeanPostProcessor
    1. 如果有@PostConstruct注解,则调用之;(前置处理阶段,AOP)
    2. 将属性注入到Bean中,afterPropertiesSet;
    3. 初始化bean,init-method;
    4. 执行postProcessor修饰bean,并用返回的bean替换到当前bean;(后置处理阶段)

pic

controller处理方法返回值的可选类型:

  • ModelAndView
    ModelAndView构造函数可以指定返回页面的名称,也可以通过setViewName方法来设置所需要跳转的页面;
  • Model
    一个模型对象,主要包含spring封装好的model和modelMap,以及java.util.Map,当没有视图返回的时候视图名称将由requestToViewNameTranslator决定;
  • View
    这个时候如果在渲染页面的过程中模型的话,就会给处理器方法定义一个模型参数,然后在方法体里面往模型中添加值。
  • String
    返回字符串表示一个视图名称,这个时候如果需要在渲染视图的过程中需要模型的话,就可以给处理器添加一个模型参数,然后在方法体往模型添加值就可以了,
  • Void
    当返回类型为Void的时候,则响应的视图页面为对应着的访问地址:这个时候我们一般是将返回结果写在了HttpServletResponse 中了,如果没写的话,spring就会利用RequestToViewNameTranslator 来返回一个对应的视图名称。如果这个时候需要模型的话,处理方法和返回字符串的情况是相同的。

事务管理

注解及接口:@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理;@Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用; 避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效;

传播机制:

  • OPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  • OPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
  • OPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
  • OPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
  • OPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起,执行当前逻辑,结束后恢复上下文的事务。
  • OPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。

默认传播机制:PROPAGATION_REQUIRED;

AOP

  • Aspect切面:一个分布在应用程序中多个位置的标准代码/功能,通常与实际的业务逻辑(例如事务管理)不同。 每个切面都侧重于一个特定的横切功能。
  • Joinpoint连接点:这是程序执行中的特定点,如方法执行,构调用造函数或字段赋值等。
  • Advice通知:在一个连接点中,切面采取的行动。
  • Pointcut切点:一个匹配连接点的正则表达式。 每当任何连接点匹配一个切入点时,就执行与该切入点相关联的指定通知。
  • Weaving织入:链接切面和目标对象来创建一个通知对象的过程。

AOP之所以能够为动态生成的Bean提供代理,得益于PostProcessor接口。在IOC初始化流程中,最后一部,就是得到BeanFactory之中所有继承了PostProcessor接口的bean,调用它们的postProcessBeforeInitilization、postProcessAfterInitilization方法,来代理bean,生成新的bean。
Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

AspectJ织入方式

编译时织入:AspectJ编译器同时加载我们切面的源代码和我们的应用程序,并生成一个织入后的类文件作为输出。 编译后织入:这就是所熟悉的二进制织入。它被用来编织现有的类文件和JAR文件与我们的切面。 加载时织入:这和之前的二进制编织完全一样,所不同的是织入会被延后,直到类加载器将类加载到JVM。

Spring AOP织入方式

运行时织入,在使用目标对象的代理执行应用程序时,编译这些切面(使用JDK动态代理或者CGLIB代理)。

Spring AOP

是一个基于代理的AOP框架。这意味着,要实现目标对象的切面,将会创建目标对象的代理类。这可以通过下面两种方式实现:

JDK动态代理:Spring AOP的首选方法。 每当目标对象实现一个接口时,就会使用JDK动态代理。 CGLIB代理:如果目标对象没有实现接口,则可以使用CGLIB代理。

不能跨越“final”的类来应用横切关注点(或切面),因为它们不能被覆盖,从而导致运行时异常。

同样地,也不能应用于静态和final的方法。由于不能覆写,Spring的切面不能应用于他们。因此,Spring AOP由于这些限制,只支持执行方法的连接点。 切面不适用于同一个类中调用的方法。这很显然,当我们在同一个类中调用一个方法时,我们并没有调用Spring AOP提供的代理的方法。

springboot原理

  • @SpringBootApplication:@Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合
  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
  • @ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
  • @Configuration:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类,
    • 在@Configuration中被@Bean标记的方法,会被Spring进行CGLIB代理,从而进行增强。 在获取到所有的bean defenition之后,Spring会有一些post process执行,其中一个就是ConfigurationClassPostProcessor, 在这里,Spring会遍历所有的bean definition, 如果发现其中有标记了@Configuration注解的,会对这个类进行CGLIB代码,生成一个代理的类,并且把这个类设置到BeanDefenition的Class属性中。当需要拿到这个bean的实例的时候,会从这个class属性中拿到的Class对象进行反射,那么最终反射出来的是代理增强后的类。
    • Configuration注解是被初始化的流程:
    AbstractApplicationContext::refresh-->AbstractApplicationContext::invokeBeanFactoryPostProcessors
    -->ConfigurationClassPostProcessor::postProcessBeanFactory-->ConfigurationClassPostProcessor::enhanceConfigurationClasses
    
    • 对于@Bean标记的方法,返回的都是一个bean,在增强的方法中,Spring会先去容器中查看一下是否有这个bean的实例了,如果有了的话,就返回已有对象,没有的话就创建一个,然后放到容器中。
  • @RestController注解是@Controller和@ResponseBody的合集

Spring5

  • 1,对jdk8增强,jdk9兼容;
  • 2,函数式编程支持;
  • 3,HTTP/2;
  • 4,反应式编程模型;