1 IOC容器

1.1 发展史

01.SpringlOC容器:通过容器来实现对象组件的装配和管理
    a.创建对象
    b.给对象的属性赋值

02.SpringIOC发展史
    new -> 简单工厂 -> SpringIOC控制反转,创建->拿,更名为“DI(依赖注入)”
    <1>Spring中“直接利用接口方法的多态性”来“产生不同的对象”
    <2>Spring中“利用工厂中使用接口方法的多态性”来“产生不同的对象”,再由Student使用“工厂”获取“不同的对象”
    <3>先向IOC容器中注入对象,再Spring中利用“工厂”获取“IOC容器的对像”,再通过“接口方法的多态性”获取不同的对象
    <4>直接从IOC容器中获取对象,再通过“接口方法的多态性”获取不同的对象
    ---------------------------------------------------------------------------------------------------------
    阶段一:类 -> new      ->对象
    阶段二:类 -> 工厂模式 ->对象:虽然可以解耦合,但问题是,需要自己编写工厂
    阶段三:类 -> IOC      ->对象:IOC提供一个超级工厂(注入对象,XML/注解)

03.IOC(控制反转),也称为DI(依赖注入):【工厂模式+反射机制】
    ①依赖注入(社会主义):将属性值注入给了属性,将属性注入给了bean,再将bean注入给了IOC容器
    ②控制反转:将创建对象、属性值的方式进行了翻转,从【new、setXxx()】翻转为【从springlOC容器getBean()】
    总结:IOC/DI,无论要什么对象,都可以直接去SpringIOC容器中获取,而不需要自己操作(new\setXxx)
    因此,之后IOC可以分为2步:1.先给springIOC中存放对象并赋值【依赖注入】 2.拿【控制反转】

04.依赖注入是控制反转的一种具体实现方式
    依赖注入(Dependency Injection)和控制反转(Inversion of Control)虽然相关,但它们不是完全相同的概念。
    依赖注入是一种软件设计模式,用于实现对象之间的解耦。在依赖注入中,一个对象的依赖关系由外部的调用者或者容器在创建对象时注入进去,而不是由对象自己创建或查找依赖。这种方式可以减少类之间的直接耦合,提高代码的可测试性、可维护性和可扩展性。
    控制反转(Inversion of Control)是一种更广泛的概念,用来描述将控制权交给外部的机制。在控制反转中,某个框架或容器负责管理对象的创建和生命周期,对象自身只需要声明它所需的依赖关系,具体的实例化和注入由框架或容器来完成。这种方式将应用程序的控制权反转给了框架或容器,从而实现了松耦合和可扩展性。
    因此,依赖注入是实现控制反转的一种具体方式。依赖注入是控制反转的一部分,它通过将依赖关系从对象内部移到外部来实现解耦,从而实现了控制反转的效果。但是,控制反转还可以包括其他形式的解耦机制,如事件驱动、回调函数等。
    总结起来,依赖注入是控制反转的一种具体实现方式,用于实现对象之间的解耦,提高代码的可测试性和可维护性。控制反转是一个更广泛的概念,描述的是将控制权交给外部的机制,包括依赖注入在内的多种实现方式

1.2 两种容器

01.Spring 配置文件支持两种格式,即 XML 文件格式和 Properties 文件格式。
    第1种:Properties 配置文件主要以 key-value 键值对的形式存在,只能赋值,不能进行其他操作,适用于简单的属性配置
    第2种:XML 配置文件采用树形结构,结构清晰,相较于 Properties 文件更加灵活。但是 XML 配置比较繁琐,适用于大型的复杂的项目
    通常情况下,Spring 的配置文件都是使用 XML 格式的。
    XML 配置文件的根元素是 <beans>,该元素包含了多个子元素 <bean>。
    每一个 <bean> 元素都定义了一个 Bean,并描述了该 Bean 是如何被装配到 Spring 容器中的。

02.Spring提供了以下两种不同类型的容器
    1.Spring BeanFactory 容器
    这是最简单的容器DI提供基本的支持和定义由org.springframework.beans.factory.BeanFactory 接口. BeanFactory或者相关的接口,例如实现BeanFactoryAware,InitializingBean,DisposableBean,仍然存在在Spring向后兼容性与大量的与Spring整合第三方框架的目的。
    2.Spring ApplicationContext 容器
    此容器添加了更多的企业特定的功能,例如从一个属性文件解析文本消息的能力,并发布应用程序事件感兴趣的事件监听器的能力。此容器是由 org.springframework.context.ApplicationContext 接口定义.

03.Spring的IOC支持哪些功能
    依赖注入和检查
    各种类型的自动装配
    指定初始化方法和销毁方法
    支持回调某些方法(但是需要实现 Spring 接口,略有侵入)

04.Spring框架中都用到了哪些设计模式?
    工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
    单例模式:Bean默认为单例模式。
    代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
    模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
    观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。

1.3 附:Spring注解

01.分类1
    @Controller                     组合注解(组合了@Component注解),应用在MVC层(控制层),DispatcherServlet会自动扫描注解了此注解的类,然后将web请求映射到注解了@RequestMapping的方法上。
    @Service                        组合注解(组合了@Component注解),应用在service层(业务逻辑层)
    @Reponsitory                    组合注解(组合了@Component注解),应用在dao层(数据访问层)
    @Component                      表示一个带注释的类是一个“组件”,成为Spring管理的Bean。当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时@Component还是一个元注解。
    @Autowired                      @Autowired可以用于属性注入、setter注入、构造方法注入的依赖注入形式
    @Resource                       JSR-250提供的注解
    @Inject                         JSR-330提供的注解
    @Configuration                  声明当前类是一个配置类(相当于一个Spring配置的xml文件)
    @ComponentScan                  自动扫描指定包下所有使用@Service,@Component,@Controller,@Repository的类并注册

02.分类2
    @Bean                           注解在方法上,声明当前方法的返回值为一个Bean。返回的Bean对应的类中可以定义init()方法和destroy()方法,然后在@Bean(initMethod=”init”,destroyMethod=”destroy”)定义,在构造之后执行init,在销毁之前执行destroy。
    @Aspect                         声明一个切面(就是说这是一个额外功能)
    @After                          后置建言(advice),在原方法前执行。
    @Before                         前置建言(advice),在原方法后执行。
    @Around                         环绕建言(advice),在原方法执行前执行,在原方法执行后再执行(@Around可以实现其他两种advice)
    @PointCut                       声明切点,即定义拦截规则,确定有哪些方法会被切入
    @Transactional                  声明事务(一般默认配置即可满足要求,当然也可以自定义)
    @Cacheable                      声明数据缓存
    @EnableAspectJAutoProxy         开启Spring对AspectJ的支持
    @Value                          值得注入。经常与Sping EL表达式语言一起使用,注入普通字符,系统属性,表达式运算结果,其他Bean的属性,文件内容,网址请求内容,配置文件属性值等等
    @PropertySource                 指定文件地址。提供了一种方便的、声明性的机制,用于向Spring的环境添加PropertySource。与@configuration类一起使用。
    @PostConstruct                  标注在方法上,该方法在构造函数执行完成之后执行。
    @PreDestroy                     标注在方法上,该方法在对象销毁之前执行。

03.分类3
    @Profile                        表示当一个或多个指定的文件是活动的时,一个组件是有资格注册的。使用@Profile注解类或者方法,达到在不同情况下选择实例化不同的Bean。@Profile(“dev”)表示为dev时实例化。
    @EnableAsync                    开启异步任务支持。注解在配置类上。
    @Async                          注解在方法上标示这是一个异步方法,在类上标示这个类所有的方法都是异步方法。
    @EnableScheduling               注解在配置类上,开启对计划任务的支持。
    @Scheduled                      注解在方法上,声明该方法是计划任务。支持多种类型的计划任务:cron,fixDelay,fixRate
    @Conditional                    根据满足某一特定条件创建特定的Bean
    @Enable*                        通过简单的@Enable*来开启一项功能的支持。所有@Enable*注解都有一个@Import注解,@Import是用来导入配置类的,这也就意味着这些自动开启的实现其实是导入了一些自动配置的Bean(1.直接导入配置类2.依据条件选择配置类3.动态注册配置类)
    @RunWith                        这个是Junit的注解,springboot集成了junit。一般在测试类里使用:@RunWith(SpringJUnit4ClassRunner.class) — SpringJUnit4ClassRunner在JUnit环境下提供Sprng TestContext Framework的功能
    @ContextConfiguration           用来加载配置ApplicationContext,其中classes属性用来加载配置类:@ContextConfiguration(classes = {TestConfig.class(自定义的一个配置类)})
    @ActiveProfiles                 用来声明活动的profile–@ActiveProfiles(“prod”(这个prod定义在配置类中))
    @EnableWebMvc                   用在配置类上,开启SpringMvc的Mvc的一些默认配置:如ViewResolver,MessageConverter等。同时在自己定制SpringMvc的相关配置时需要做到两点:1.配置类继承WebMvcConfigurerAdapter类2.就是必须使用这个@EnableWebMvc注解。

04.分类4
    @RequestMapping                 用来映射web请求(访问路径和参数),处理类和方法的。可以注解在类和方法上,注解在方法上的@RequestMapping路径会继承注解在类上的路径。同时支持Serlvet的request和response作为参数,也支持对request和response的媒体类型进行配置。其中有value(路径),produces(定义返回的媒体类型和字符集),method(指定请求方式)等属性。                                 |
    @ResponseBody                   将返回值放在response体内。返回的是数据而不是页面
    @RequestBody                    允许request的参数在request体中,而不是在直接链接在地址的后面。此注解放置在参数前。
    @PathVariable                   放置在参数前,用来接受路径参数。
    @RestController                 组合注解,组合了@Controller和@ResponseBody,当我们只开发一个和页面交互数据的控制层的时候可以使用此注解。
    @ControllerAdvice               用在类上,声明一个控制器建言,它也组合了@Component注解,会自动注册为Spring的Bean。
    @ExceptionHandler               用在方法上定义全局处理,通过他的value属性可以过滤拦截的条件:@ExceptionHandler(value=Exception.class)–表示拦截所有的Exception。
    @ModelAttribute                 将键值对添加到全局,所有注解了@RequestMapping的方法可获得次键值对(就是在请求到达之前,往model里addAttribute一对name-value而已)。
    @InitBinder                     通过@InitBinder注解定制WebDataBinder(用在方法上,方法有一个WebDataBinder作为参数,用WebDataBinder在方法内定制数据绑定,例如可以忽略request传过来的参数Id等)。
    @WebAppConfiguration            一般用在测试上,注解在类上,用来声明加载的ApplicationContext是一个WebApplicationContext。他的属性指定的是Web资源的位置,默认为src/main/webapp,我们可以修改为:@WebAppConfiguration(“src/main/resources”)。
    @EnableAutoConfiguration        此注释自动载入应用程序所需的所有Bean——这依赖于Spring Boot在类路径中的查找。该注解组合了@Import注解,@Import注解导入了EnableAutoCofigurationImportSelector类,它使用SpringFactoriesLoader.loaderFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包。而spring.factories里声明了有哪些自动配置。
    @SpingBootApplication           SpringBoot的核心注解,主要目的是开启自动配置。它也是一个组合注解,主要组合了@Configurer,@EnableAutoConfiguration(核心)和@ComponentScan。可以通过@SpringBootApplication(exclude={想要关闭的自动配置的类名.class})来关闭特定的自动配置。
    @ImportResource                 虽然Spring提倡零配置,但是还是提供了对xml文件的支持,这个注解就是用来加载xml配置的。例:@ImportResource({“classpath
    @ConfigurationProperties        将properties属性与一个Bean及其属性相关联,从而实现类型安全的配置。例:@ConfigurationProperties(prefix=”authot”,locations={“classpath

05.分类5
    @ConditionalOnBean              条件注解。当容器里有指定Bean的条件下。
    @ConditionalOnClass             条件注解。当类路径下有指定的类的条件下。
    @ConditionalOnExpression        条件注解。基于SpEL表达式作为判断条件。
    @ConditionalOnJava              条件注解。基于JVM版本作为判断条件。
    @ConditionalOnJndi              条件注解。在JNDI存在的条件下查找指定的位置。
    @ConditionalOnMissingBean       条件注解。当容器里没有指定Bean的情况下。
    @ConditionalOnMissingClass      条件注解。当类路径下没有指定的类的情况下。
    @ConditionalOnNotWebApplication 条件注解。当前项目不是web项目的条件下。
    @ConditionalOnResource          条件注解。类路径是否有指定的值。
    @ConditionalOnSingleCandidate   条件注解。当指定Bean在容器中只有一个,后者虽然有多个但是指定首选的Bean。
    @ConditionalOnWebApplication    条件注解。当前项目是web项目的情况下。
    @EnableConfigurationProperties  注解在类上,声明开启属性注入,使用@Autowired注入。例:@EnableConfigurationProperties(HttpEncodingProperties.class)。
    @AutoConfigureAfter             在指定的自动配置类之后再配置。例:@AutoConfigureAfter(WebMvcAutoConfiguration.class)

1.4 附:Spring设计模式

01.Spring使用的设计模式
    a.简单工厂
        Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。
    b.工厂方法
        实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是,spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean的getOjbect()方法的返回值。
    c.单例模式
        Spring依赖注入Bean实例默认是单例的。Spring的依赖注入(包括lazy-init方式)都是发生在AbstractBeanFactory的getBean里。getBean的doGetBean方法调用getSingleton进行bean的创建。
    d.适配器模式
        SpringMVC中的适配器HandlerAdatper,它会根据Handler规则执行不同的Handler。即DispatcherServlet根据HandlerMapping返回的handler,向HandlerAdatper发起请求处理Handler。HandlerAdapter根据规则找到对应的Handler并让其执行,执行完毕后Handler会向HandlerAdapter返回一个ModelAndView,最后由HandlerAdapter向DispatchServelet返回一个ModelAndView。
    e.装饰器模式
        Spring中用到的装饰器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。
    f.代理模式
        AOP底层就是动态代理模式的实现。即:切面在应用运行的时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象创建动态的创建一个代理对象。SpringAOP就是以这种方式织入切面的。
    g.观察者模式
        Spring的事件驱动模型使用的是观察者模式,Spring中Observer模式常用的地方是listener的实现。
    h.策略模式
        Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring 框架本身大量使用了 Resource 接口来访问底层资源。Resource 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口。
    i.模板方法模式
        Spring模板方法模式的实质,是模板方法模式和回调模式的结合,是Template Method不需要继承的另一种实现方式。Spring几乎所有的外接扩展都采用这种模式。

02.Spring使用的设计模式
    ①工厂模式:创建bean,获取bean
    ②单例模式/原型模式:创建bean,设置作用域
    ③监听模式:自定义事件发布,例如ApplicationListener,当某个动作触发时,会自动执行一个通知
    ④责任链模式:AOP
    ⑤策略模式:创建代理

2 Bean基础概念

2.1 定义

01.定义
    由Spring IOC容器管理的对象称为 Bean
    我们可以把 Spring IoC 容器看作是一个大工厂,Bean 相当于工厂的产品。

2.2 作用域

01.Spring中的bean的作用域
    singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
    prototype : 每次请求都会创建一个新的 bean 实例。
    request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
    session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
    global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

02.对于普通的 Java 对象来说,它们的生命周期就是:
    实例化
    该对象不再被使用时通过垃圾回收机制进行回收

03.对于 Spring Bean 的生命周期来说:实例化 -> 属性赋值 -> 初始化 -> 销毁
    实例化 Instantiation
    属性赋值 Populate
    初始化 Initialization
    销毁 Destruction

2.3 执行时机

2.4 加载时机

2.5 条件注解

00.条件注解目的
    让某一个Bean在某些条件下加入IOC容器,其他情况下不加IOC容器

2.6 生命周期

01.Spring中的bean的作用域
    singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
    prototype : 每次请求都会创建一个新的 bean 实例。
    request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
    session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
    global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

02.对于普通的 Java 对象来说,它们的生命周期就是:
    实例化
    该对象不再被使用时通过垃圾回收机制进行回收

03.对于 Spring Bean 的生命周期来说:实例化 -> 属性赋值 -> 初始化 -> 销毁
    实例化 Instantiation
    属性赋值 Populate
    初始化 Initialization
    销毁 Destruction

3 Bean注入方式

3.1 介绍

01.如何给Spring容器提供配置元数据?Spring有几种配置方式
    XML配置文件
    基于注解的配置
    基于java的配置

02.什么是bean的自动装配?
    在Spring框架中,在配置文件中设定bean的依赖关系是一个很好的机制,Spring 容器能够自动装配相互合作的bean,
    这意味着容器不需要和配置,能通过Bean工厂自动处理bean之间的协作。这意味着 Spring可以通过向Bean Factory中
    注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,也可以设定在特定的bean上。

03.使用@Autowired注解自动装配的过程是怎样的?
    使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。
    在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
    如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
    如果查询的结果不止一个,那么@Autowired会根据名称来查找;
    如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

04.存Bean:XML方式(Bean标签)、
    五大类注解(@Controller、@Service、@Repository、@Component、@Configuration)、
    方法注解(@Bean)

05.取Bean:基本方法、
    注解方法(属性注入、set注入、构造方法注入)

06.说明
    IOC容器赋值 / 存Bean / 依赖注入 / 控制反转 / 自动装配是Spring框架中一种方便的依赖注入方式
    IOC容器取值 / 取Bean
    ---------------------------------------------------------------------------------------------------------
    IOC容器赋值/IOC容器取值(IOC Container Wiring/Retrieval):IOC容器赋值是指在IOC容器中配置Bean之间的依赖关系,即将对象的依赖关系交给IOC容器来管理。IOC容器取值是从IOC容器中获取已经配置的Bean的实例。在IOC容器赋值阶段,配置文件或注解定义了Bean之间的依赖关系;而在IOC容器取值阶段,通过调用IOC容器的API(如ApplicationContext.getBean())来获取已经在容器中配置的Bean的实例。
    存Bean/取Bean(Bean Definition/Bean Retrieval):存Bean是将Bean的定义或配置注册到IOC容器中。这包括Bean的名称、类型、作用域、属性值等信息。取Bean是从IOC容器中获取已经注册的Bean的实例,以便在应用程序中使用。存Bean是将Bean的定义存储到IOC容器中,取Bean是通过IOC容器获取已经在容器中注册的Bean的实例。
    依赖注入(Dependency Injection):依赖注入是一种实现IOC的方式,用于解决对象之间的依赖关系。通过依赖注入,对象的依赖关系由外部的调用者或IOC容器在创建对象时注入进去,而不是由对象自己创建或查找依赖。依赖注入实现了对象之间的解耦,提高了代码的可测试性、可维护性和可扩展性。
    控制反转(Inversion of Control):控制反转是一种设计原则,用于将应用程序的控制权交给框架或容器。控制反转实现了对对象的创建和管理的反转,由框架或容器来负责对象的创建、配置和生命周期管理,而不是由对象自己去创建和管理。依赖注入是控制反转的一种具体实现方式。
    自动装配(Autowiring):自动装配是IOC容器中的一种便捷的依赖注入方式。通过自动装配,IOC容器根据指定的规则(如byName、byType、constructor、autodetect等)自动解析和注入Bean之间的依赖关系,无需显式地指定依赖关系。自动装配可以减少手动配置的工作量,提高开发效率。
    ---------------------------------------------------------------------------------------------------------
    综上所述,IOC容器赋值和IOC容器取值是IOC容器中配置Bean和获取Bean的过程;
    存Bean和取Bean是将Bean的定义注册到IOC容器中和从IOC容器中获取Bean实例的过程;
    依赖注入是一种实现IOC的方式,用于解决对象之间的依赖关系;
    控制反转是将应用程序的控制权交给框架或容器的设计原则;
    自动装配是IOC容器中的一种便捷的依赖注入方式。
    ---------------------------------------------------------------------------------------------------------
    依赖注入的本质就是装配一自动装配:Spring可以使用xml和注解来进行自动装配。
    自动装配就是开发人员不必知道具体要装配哪个bean的引用,这个识别的工作会由spring来完成,自动装配就是为了将依赖注入“自动化"的一个简化配置的操作

07.说明
    各种IOC容器“互相独立"
    ---------------------------------------------------------------------------------------------------------
    Spring提供了以下两种不同类型的容器
    1.Spring BeanFactory 容器
    这是最简单的容器DI提供基本的支持和定义由org.springframework.beans.factory.BeanFactory 接口. BeanFactory或者相关的接口,例如实现BeanFactoryAware,InitializingBean,DisposableBean,仍然存在在Spring向后兼容性与大量的与Spring整合第三方框架的目的。

    2.Spring ApplicationContext 容器
    此容器添加了更多的企业特定的功能,例如从一个属性文件解析文本消息的能力,并发布应用程序事件感兴趣的事件监听器的能力。此容器是由 org.springframework.context.ApplicationContext 接口定义.
    -----------------------------------------------------------------------------------------------------
    带有@Configuration注解的类(配置类)属于【2.Spring ApplicationContext 容器】
    @Configuration注解是Spring框架中的注解之一,用于标识一个类是配置类,其中定义了一些用于创建和配置Bean的方法。配置类通常用于替代传统的XML配置文件,提供了一种更加便捷和类型安全的配置方式。
    在Spring中,ApplicationContext是BeanFactory的子接口,提供了更多的功能和特性。ApplicationContext容器负责管理Bean的生命周期、依赖注入、AOP、国际化等方面的功能,并提供了更强大的应用程序上下文和依赖注入功能。因此,带有@Configuration注解的类通常会被注册到ApplicationContext容器中,作为配置信息的一部分。
    通过@Configuration注解标记的类会被Spring容器扫描并解析,创建对应的Bean定义,并将其纳入ApplicationContext容器的管理范围。这样,配置类中定义的Bean就可以在应用程序中被注入和使用。
    总结起来,带有@Configuration注解的类属于ApplicationContext容器。它们是配置类,在Spring框架中用于创建和配置Bean,并被注册到ApplicationContext容器中进行管理。

08.第一种:【xml配置文件:applicationContext.xml】
    ①存Bean:<bean id="class=">
        ①set注入:通过setXxx()赋值,默认
        ②有参构造器注入:通过构造方法赋值
        ③p命名空间注入
        ④字段注入:第1种:@Autowired(Spring提供):默认,根据类型查找
                  第2种:@Resource(USR250提供):默认,先根据名字查找,再根据类型查找
                  第3种:@Resource(JSR330):默认,根据类型查找,需要引入jar包(javax.inject.jar)
    ②取Bean
        public static void testDI(){
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            Course course =(Coursecontext.getBean("course");
            course.showInfo();
        }
    ---------------------------------------------------------------------------------------------------------
    ③注入各种集合数据类型的装配
        List、arrry、set、map、properties
    ④自动装配(只适用于对象类型 ):约定优于配置
        a.byName(byId)
        b.byType
        c.constructor(本质byType)
        d.自动:头文件,一次性为所有bean全部装配

09.第二种:【注解:带有@Configuration注解的类(配置类)】
    a.存Bean
        1.三层注解=三层注解+扫描器
            ①三层注解:@Controller、@Service、@Repository
            ②功能性注解(不清楚是否为三层注解时,也可使用):@Component
            -------------------------------------------------------------------------------------------------
            扫描器:第1种(XML)、第2种(配置类)
        2.非三层注解:
            ①@Bean+方法的返回值
            ②@import
            ③FactoryBean(Bean)
        -----------------------------------------------------------------------------------------------------
        示例(最简单的一种):
            @Configuration
            public class MyConfig
                @Bean
                public Student myStudent(){
                    Student student = new Student(100, "zs", 88);
                    student.setAddress(new Address("xa", "bj"));
                    return student;
                }
            }
    ②取Bean
        ApplicationContext context new AnnotationConfigApplicationContext(MyConfig.class);
        context.getBean();

3.2 第一种:【XML配置文件:applicationContext.xml】

01.第一种:【xml配置文件:applicationContext.xml】
    ①存Bean:<bean id="class=">
        ①set注入:通过setXxx()赋值,默认
        ②有参构造器注入:通过构造方法赋值
        ③p命名空间注入
        ④字段注入:第1种:@Autowired(Spring提供):默认,根据类型查找
                  第2种:@Resource(USR250提供):默认,先根据名字查找,再根据类型查找
                  第3种:@Resource(JSR330):默认,根据类型查找,需要引入jar包(javax.inject.jar)
    ②取Bean
        public static void testDI(){
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            Course course =(Coursecontext.getBean("course");
            course.showInfo();
        }
    ---------------------------------------------------------------------------------------------------------
    ③注入各种集合数据类型的装配
        List、arrry、set、map、properties
    ④自动装配(只适用于对象类型):约定优于配置
        a.byName(byId)
        b.byType
        c.constructor(本质byType)
        d.自动:头文件,一次性为所有bean全部装配

02.第一种:【xml配置文件:applicationContext.xml】
    a.常用的三种注入方式
        依赖注入(Dependency Injection)是实现控制反转(Inversion of Control)的一种方式,它可以通过不同的方式来实现对象之间的依赖注入。以下是依赖注入的三种常见方式:
        -----------------------------------------------------------------------------------------------------
        第1种:构造函数注入(Constructor Injection):通过构造函数来实现依赖注入。在这种方式下,依赖关系通过对象的构造函数参数进行注入。对象在被创建时,其构造函数会接受所需的依赖对象作为参数,并将其保存在成员变量中以供后续使用。这种方式可以在对象创建时就确保其依赖关系已经被注入,并且使得对象在创建后是不可变的(immutable)。
        public class MyClass {
           private MyDependency myDependency;

           public MyClass(MyDependency myDependency) {
              this.myDependency = myDependency;
           }
        }
        -----------------------------------------------------------------------------------------------------
        第2种:Setter方法注入(Setter Injection):通过setter方法来实现依赖注入。在这种方式下,对象提供一组setter方法,通过这些方法将依赖对象注入到成员变量中。在对象创建后,容器会调用相应的setter方法,将依赖对象传递给对象并进行赋值。这种方式允许依赖关系的动态更改,并且使得对象的创建和依赖注入可以分离。
        public class MyClass {
           private MyDependency myDependency;

           public void setMyDependency(MyDependency myDependency) {
              this.myDependency = myDependency;
           }
        }
        -----------------------------------------------------------------------------------------------------
        第3种:字段注入(Field Injection):通过直接注入成员变量来实现依赖注入。在这种方式下,对象的依赖关系直接通过注解或修饰符来标记在成员变量上,容器在对象创建后直接将依赖对象注入到成员变量中。这种方式简化了代码,但也会增加对象对容器的依赖。
        public class MyClass {
           @Autowired
           private MyDependency myDependency;
        }
            -------------------------------------------------------------------------------------------------
            @Autowired:可用于构造函数、成员变量、Setter方法
            @Qualifier:当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,您可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 bean 来消除歧义。
            -------------------------------------------------------------------------------------------------
            @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
            @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
            -------------------------------------------------------------------------------------------------
            a.第1种:@Autowired(Spring提供):默认,根据类型查找
                1.属性前标注@Autowired,则不调用setXxx
                2.方法前标注@Autowired三处位置
                    a.setXxx方法前标注,则调用setXxx
                    b.普通方法前
                    c.c.构造方法前(特殊),如果只有一个有参构造方法,则构造方法前的@Autowired也可以省略
                3.方法参数前标注@Autowired:两类情况
                    a.三层注入方式,不会自动注入,结果为null
                    b.Bean+返回值(可以省略@Autowired),自动从IOC容器中寻找一个类型为Address的Bean
                ---------------------------------------------------------------------------------------------
                提问:三层注入方式/@Bean+返回值?
                1.如果有多个类型相同的,匹配哪个?报错/默认值@primary
                    a.三层注入方式:报错
                    b.@Bean+返回值:报错
                2.能否根据名字匹配?@Autowired+@Qualifier
                    a.三层注入方式:@Autowired+@Qualifier
                    b.@Bean+返▣值:@Autowired+@Qualifier
                3.如果有0个类型相同?默认报错,可以修改成不注入(null)@Autowired(required=false)
                    a.三层注入方式:默认,报错
                    b.可以修改成不注入(null),@Autowired(required=false)
            -------------------------------------------------------------------------------------------------
            b.第2种:@Resource(USR250提供):默认,先根据名字查找,再根据类型查找
                1.默认根据名字
                    a.如果有名字,根据名字匹配:
                    b.如果没有名字,先根据名字查找,如果没找到,再根据类型查找
                2.也可以通过name或type属性,指定根据名字或类型找
            -------------------------------------------------------------------------------------------------
            c.第3种:@Resource(JSR330):默认,根据类型查找,需要引入jar包(javax.inject.jar)
    b.构造函数注入、setter注入的区别
       【构造函数注入】                         【setter注入】
        没有部分注入                             有部分注入
        不会覆盖 setter 属性                     会覆盖 setter 属性
        任意修改都会创建一个新实例                任意修改不会创建一个新实例
        适用于设置很多属性                       适用于设置少量属性

3.3 第二种:【注解:带有@Configuration注解的类(配置类)】

01.第二种:【注解:带有@Configuration注解的类(配置类)】
    a.存Bean
        1.三层注解=三层注解+扫描器
            ①三层注解:@Controller、@Service、@Repository
            ②功能性注解(不清楚是否为三层注解时,也可使用):@Component
            -------------------------------------------------------------------------------------------------
            扫描器:第1种(XML)、第2种(配置类)
        2.非三层注解:
            ①@Bean+方法的返回值
            ②@import
            ③FactoryBean(Bean)
        -----------------------------------------------------------------------------------------------------
        示例(最简单的一种):
            @Configuration
            public class MyConfig
                @Bean
                public Student myStudent(){
                    Student student = new Student(100, "zs", 88);
                    student.setAddress(new Address("xa", "bj"));
                    return student;
                }
            }
    ②取Bean
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        context.getBean();

3.4 避免使用注解注入

01.Spring 官方推荐避免使用注解注入,而是通过构造器或 set 方法注入依赖
    1.控制反转原则:注解注入暴露对容器的依赖,与 ioc 理念相悖。
    2.依赖关系:构造器注入明确展示依赖关系和数量顺序,便于理解和维护。
    3.类灵活性:属性注入限制类在容器之外的实例化,限制类的可重用性和灵活性。
    4.错误捕获:构造器注入在实例化阶段捕获依赖注入错误,避免空指针异常。
    5.单元测试:属性注入导致对象与其依赖关系紧密耦合,不利于单元测试。

4 AOP切面编程

4.1 介绍

01.什么是AOP
    OOP(Object-Oriented Programming)面向对象编程,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
    AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。

02.AOP分为两步:
    1、动态生成代理类;
        一个类被 AOP 织入增强后,就产生了一个结果类,它融合了原类和增强逻辑的代理类 。
        根据不同的代理方式,代理类可能是与原类具有相同接口的类,也可能是原类的子类。
    2、织入;
        织入是将增强添加到目标的具体连接点上的过程 。
        编译期织入 特殊的 Java 编译器。 AspectJ
        类装载期织入 特殊的类装载器。 AspectJ
        动态代理织入 在运行期为目标类添加增强生成子类的方式。 Spring

03.AOP应用场景
    场景一: 记录日志
    场景二: 监控方法运行时间 (监控性能)
    场景三: 权限控制
    场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
    场景五: 事务管理 (调用方法前开启事务, 调用方法后提交关闭事务 ,如声明式事务)

04.解释一下Spring AOP里面的几个名词
    (1)切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了切面的全部内容。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。
    (2)连接点(Join point):指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。 应用可能有数以千计的时机应用通知。这些时机被称为连接点。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
    (3)通知(Advice):在AOP术语中,切面的工作被称为通知。
    (4)切入点(Pointcut):切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。
    (5)引入(Introduction):引入允许我们向现有类添加新方法或属性。
    (6)目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。它通常是一个代理对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
    (7)织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。在目标对象的生命周期里有多少个点可以进行织入:

05.Spring通知有哪些类型?
    前置通知(Before):在目标方法被调用之前调用通知功能;
    后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
    返回通知(After-returning ):在目标方法成功执行之后调用通知;
    异常通知(After-throwing):在目标方法抛出异常后调用通知;
    环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

06.什么是切面Aspect?
    aspect 由 pointcount 和 advice 组成,切面是通知和切点的结合。 它既包含了横切逻辑的定义, 也包括了连接点的定义.
    Spring AOP 就是负责实施切面的框架, 它将切面所定义的横切逻辑编织到切面所指定的连接点中.
    AOP 的工作重心在于如何将增强编织目标对象的连接点上, 这里包含两个工作:
    如何通过 pointcut 和 advice 定位到特定的 joinpoint 上
    如何在 advice 中编写切面代码.
    可以简单地认为, 使用 @Aspect 注解的类就是切面.

07.面向对象/面向切面
    面向对象缺陷:
    1.方法名:父类一改,其他子类都得跟上改动
    2.编写逻辑:父类一改,其他子类都得跟上改动
    ---------------------------------------------------------------------------------------------------------
    面向切面:
    1.方法名:采取引用x()
    2.编写逻辑:切入点,只需要声明-每次调用dd后自动执行x3()

08.Spring AOP and AspectJ AOP 有什么区别?AOP 有哪些实现方式?
    AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
    (1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
    (2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

4.2 第一种:实现接口+XML

01.实现接口
    // 前置通知
    public class LogBefore implements MethodBeforeAdvice{

        //前置通知的具体内容
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("前置通知");
        }
    }

    // 后置通知
    public class LogAfter implements AfterReturningAdvice{

        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("后置通知:目标对象:" + target + ",调用的方法名:" + method.getName()
            + ",方法的参数个数:" + args.length + ",方法的返回值:" + returnValue);
        }
    }

    // 异常通知
    public class LogException implements ThrowsAdvice{
        //空实现,但是有必须要实现的方法
        void afterThrowing(Method method, Object[] args , Object target,  Throwable ex) {
            System.out.println("异常通知:目标对象:" + target + ",方法名:" + method.getName()
            + ",方法的参数个数:" + args.length + ",异常类型:" + ex.getMessage());
        }
    }

    // 环绕通知 = 前置 + 后置 + 异常
    public class LogAround implements MethodInterceptor{

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {

            Object result = null;

            try {
                System.out.println("用环绕通知实现的[前置通知] . . .");

                //invocation.proceed()之前的代码:前置通知
                result = invocation.proceed();//控制着目标方法的执行,addStudent()
                //invocation.proceed()之后的代码:后置通知

                System.out.println("用环绕通知实现的[后置通知] . . .");
                System.out.println("环绕通知:目标对象:" + invocation.getThis() + ",调用方法名:" + invocation.getMethod().getName()
                        + ",方法的参数个数:" + invocation.getArguments().length + ",返回值:" + result );

            } catch (Exception e) {
                //异常通知
                System.out.println("用环绕通知实现的[异常通知] . . .");
            }

            return result;//目标方法的返回值
        }

    }

02.XML
    aop:before表前置通知, 切入点方法执行之前执行.
    aop:after-returning配置后置通知,切入点方法正常执行之后。它和异常通知只能有一个执行;
    aop:after-throwing配置异常通知, 切入点方法执行产生异常后执行。它和后置通知只能执行一个;
    aop:after用于配置最终通知,无论切入点方法执行时是否有异常, 它都会在其后面执行.
    aop:around环绕通知

02.前置、后置、异常、环绕

4.3 第二种:普通类+XML

00.通过配置将【类->通知】,基于Schema配置,类似与实现接口的方式
    a.编写一个普通类  public class LogAfter()
    b.将该类通过配置,转为一个“通知

01.schema形式和注解形式相似,不同之处:
    ①注解形式使用了注册@After
    ②schmema形式进行了多余的配置

4.4 第三种:注解

00.示例
    /**
     * 用于记录日志的工具类
     */
    @Component("logger")
    @Aspect // 表示当前类是个切面类
    @EnableAspectJAutoProxy
    @ComponentScan(basePackages = "com.mine")
    public class Logger {

        @Pointcut("execution(* com..mine.service.impl.*.*(..))")
        private void pt(){}
        /**
         * 前置通知
         */
    //    @Before("pt()")
        public void beforePrintLog() {
            System.out.println("前置通知logger中的printLog方法开始执行了...");
        }

        /**
         * 后置通知
         */
    //    @AfterReturning("pt()")
        public void afterReturningPrintLog() {
            System.out.println("后置通知logger中的printLog方法开始执行了...");
        }

        /**
         * 异常通知
         */
    //    @AfterThrowing("pt()")
        public void afterThrowingPrintLog() {
            System.out.println("异常通知logger中的printLog方法开始执行了...");
        }

        /**
         * 最终通知
         */
    //    @After("pt()")
        public void afterPrintLog() {
            System.out.println("最终通知logger中的printLog方法开始执行了...");
        }
        @Around("pt()")
        public Object aroundPringLog(ProceedingJoinPoint pjp) {
            Object resValue = null;
            try {
                Object[] args = pjp.getArgs(); // 获取方法执行所需要的参数
                System.out.println("aroundPringLog中的logger方法开始记录日志了...前置");
                resValue = pjp.proceed(args); // 明确调用业务层的切入点方法 ....切入点方法
                System.out.println("aroundPringLog中的logger方法开始记录日志了...后置");
                return resValue;
            } catch (Throwable throwable) {
                System.out.println("aroundPringLog中的logger方法开始记录日志了...异常");
               throw new RuntimeException(throwable);
            } finally {
                System.out.println("aroundPringLog中的logger方法开始记录日志了...最终");

            }
        }
    }

00.注解
    @Aspect           表示当前类是个切面类
    @Before           前置通知
    @AfterReturning   返回通知
    @AfterThrowing    异常通知
    @After            后置通知
    @Around           环绕通知
    ---------------------------------------------------------------------------------------------------------
    前置通知(Before):在目标方法被调用之前调用通知功能;
    后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
    返回通知(After-returning ):在目标方法成功执行之后调用通知;
    异常通知(After-throwing):在目标方法抛出异常后调用通知;
    环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

5 整合项目

5.1 Spring底层组件开发

5.2 Spring整合Quartz框架

5.3 Spring整合MyBatis

5.4 Spring开发Web项目

5.5 Spring整合MyBatis、SpringMVC

5.6 SpringBoot整合JSP开发

5.7 SpringBoot开发Web项目

5.8 @Transactional:声明式事务

5.9 @EventListener:监听器