Spring5 学习总结(持续更新中)

image-20220414214145910

Spring框架笔记

一.spring概念

  1. Spring 是 一款轻量级的开源框架

  2. Spring 可以解决企业应用开发的复杂性。

  3. Spring 有两个核心部分:IOC 和 Aop

    • IOC :控制反转,把创建对象过程交给 Spring 进行管理。
    • Aop :面向切面,不修改源代码就可以进行功能的增强。
  4. Spring 特点

    • IOC 控制反转:把创建对象过程交给 Spring 进行管理,方便解耦,简化开发。
    • Aop 面向切面编程:不修改源代码就可以进行功能的增强。
    • 一站式:可以方便与其他框架优秀的第三方类库进行整合。
    • 简化 API 的使用,spring 对很多难用的 JavaEE API (如JDBC)进行了简单的封装,从而降低了一些 API 的使用难度。
    • 方便程序测试(支持Junit4测试)
    • 方便进行事务的操作

二. Spring 体系结构

Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。

Spring 框架基本涵盖了企业级应用开发的各个方面,它包含了 20 多个不同的模块。

image-20220414205110751

核心容器

  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
  • spring-core 核心模块提供了框架的基本组成部分,包括 IOC依赖注入功能。
  • Context 上下文模块建立在 Core 和 Beans 模块的基础之上,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、Java EE 支持、容器生命周期、事件传播等。ApplicationContext 接口是上下文模块的焦点。
  • **SpEL 模块:**提供了强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean,它也支持列表投影、选择和一般的列表聚合等。

数据访问/集成

数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

  • JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
  • ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。
  • OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。
  • 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细)

Web

Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

  • Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。
  • Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
  • Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。

Test模块

Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。


其他模块

  • AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。
  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
  • Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
  • Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
  • 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

三.IOC容器

什么是 IOC ?

(1)控制反转,把对象创建对象之间的调用都交给 Spring 来管理。

(2)使用 IOC 的目的:降低耦合度

IOC 底层原理

XML 的解析、工厂模式、反射

image-20220414205225524

IOC 接口(BeanFactory)

1. IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂。

2. Spring 提供 IOC 容器实现的两种方式:两个接口

(1)BeanFactory接口:是IOC容器实现的基本接口,是Spring内部接口,不提供给开发人员进行使用(加载配置文件时候不会创建对象,在获取对象时才会创建对象。)
(2)ApplicationContext接口:BeanFactory接口的子接口,提供更多更强大的功能,提供给开发人员使用(加载配置文件时候就会把在配置文件对象进行创建)(推荐使用!我们希望当程序刚启用-加载配置文件的时候就创建对象,而不是在-获取对象的时候在创建对象)

//1.加载 Spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
HelloSpring5 obj = context.getBean("helloWorld", HelloSpring5.class);
obj.getMesage();

3. ApplicationContext通常的实现是什么?(面试)

  • FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean配置文件的全路径名必须提供给它的构造函数。(对应绝对路径)

  • ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。(对应类路径)

4. IOC的优点是什么?(面试)

IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。

5. Bean 工厂和 Application contexts 有什么区别?(面试)

Application contexts提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的bean发布事件。另外,在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作,可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。

什么是 Bean 管理:

Bean 管理指的是两个操作:1. Spring 创建对象 (通过反射创建对象) 2.注入属性(设置属性值)

IOC 操作 Bean 管理(***基于XML的 Bean 管理)

1. 基于 XML 方式创建对象

image-20220414205312472

使用<Bean>标签方式创建对象

2. 基于 XML 方式注入属性

  • DI:依赖注入,就是注入属性
  • IOC 和 DI 的区别是?(面试) DI 是 IOC Bean管理操作的具体实现,它表示依赖注入,就是注入属性。

(1)set 方法注入属性(利用 property 标签注入属性)

<!--创建对象-->
<bean id="helloWorld" class="src.com.cn.java.HelloSpring5">
    <!-- 利用 property 标签注入属性-->
    <property name="mesage" value="你好" ></property>
</bean>

(2)通过有参构造方法完成注入属性 ( 利用 constructor标签注入属性 )

<bean id="book1" class="src.com.cn.java.book">
    <constructor-arg name="bname" value="易筋经"></constructor-arg>
    <constructor-arg name="bprices" value="达摩院"></constructor-arg>
</bean>

3. 基于 XML 方式注入其他类型属性

(1)注入其他属性–字面量
  • 属性设置空值

    <constructor-arg name="bbba" >
        <null></null>
    </constructor-arg>
    
  • 属性包含特殊符号,例如 <<南京>>

    <!--        把特殊符号内容写入CDATA中-->
            <constructor-arg name="bbba" >
                <value>
                    <![CDATA[<<南京>>]]>
                </value>
            </constructor-arg>
    
(2)注入其他属性–外部 Bean

(从 Service 引用 dao 层的一个类作为service层类的一个属性,需要注入dao层的一个对象(而非简单的属性),就叫做引入外部 Bean)

service层
public class userService {
    //创建UserDao类型的属性,生成Set方法
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void add(){
        userDao.addUserById();
        System.out.println("---------------");
    }
}
XML 配置如下:
<--基于set方法的对象注入如下,而基于有参构造方法的注入同理。-->
    <bean name="userService" class="src.com.service.userService">
	<!--    name是service 属性名称   ref:创建Bean标签的id值-->
        <property name="userDao" ref="userDao1"></property>
    </bean>
    <bean name="userDao1" class="src.com.dao.UserDaoImp"></bean>
(3)注入其他属性–内部 Bean 和 级联赋值

​ a.一对多关系:部门和员工------在实体类之间表示一对多的关系

<!--内部Bean写法-->
    <bean name="Emp" class="src.com.dao.Emp">
        <property name="ename" value="张"></property>
        <property name="egender" value="nv"></property>
        <!--设置对象类型属性 内部Bean写法-->
        <property name="dept ">
            <bean id="Dept" class="src.com.dao.Dept"> 
                <property name="dname" value="计算机"></property>
            </bean>
        </property>
    </bean>
与外部Bean的区别就是,级联赋值在引入外部Bean的同时,给外部Bean设置了属性。

<!--级联赋值Bean写法-->
<bean name="Emp1" class="src.com.dao.Emp">
<property name="ename" value="张"></property>
<property name="egender" value="女"></property>
<!--级联赋值-->
    <property name="dept" value="Dept2"></property></bean>
<bean name="Dept2" class="src.com.dao.Dept">
    <property name="dname" value="安保部门"></property>
</bean>
(4)注入其他属性–集合属性
  • 注入数组类型属性

  • 注入 List 集合类型属性

  • 注入 Map 集合类型属性

  • 注入set类型属性

  • 集合里面设置对象类型的属性

    <bean name="stu_bean" class="src.com.dao.stu">
    <!--        注入数组类型属性-->
            <property name="courses">
                <array>
                    <value>Java课程</value>
                    <value>数据库课程</value>
                </array>
            </property>
    <!--        注入List集合类型属性-->
            <property name="list">
                <list>
                    <value>张三</value>
                    <value>李四</value>
                </list>
            </property>
            <!--        注入Map集合类型属性-->
            <property name="map">
                <map>
                    <entry key="2017405A3" value="长女"></entry>
                    <entry key="2017405A8" value="次子"></entry>
                </map>
            </property>
    <!--        set类型属性注入-->
            <property name="set">
                <set>
                        <value>MySql</value>
                        <value>SqlServer</value>
                </set>
            </property>
        </bean>
    <!--        list集合类型,对象类型-->
            <property name="courses_list">
                <list>
                    <ref bean="course_Bean1"></ref>
                    <ref bean="course_Bean2"></ref>
                </list>
            </property>
    
        </bean>
        <bean id="course_Bean1" class="src.com.dao.course">
            <property name="cname" value="数学二"></property>
        </bean>
        <bean id="course_Bean2" class="src.com.dao.course">
            <property name="cname" value="英语二"></property>
        </bean>
    

集合里面设置对象类型如何输出

设置一个 toString

public class course {
    //课程名称
    private String cname;
public String toString() {
    return "course{" +
            "cname='" + cname + '\'' +
            '}';}
}
System.out.println(courses_list);
  • 集合里面设置对象类型的属性,将List数组提取出来

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:util="http://www.springframework.org/schema/util"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    
        <util:list id="course_BeanList">
            <ref bean="course_Bean1"></ref>
            <ref bean="course_Bean2"></ref>
        </util:list>
        <bean name="stu_bean" class="src.com.dao.stu">
            <property name="courses_list" ref="course_BeanList"></property>
    

IOC 操作 Bean 管理(FactoryBean 管理)

  1. Spring 有两种类型的 Bean:普通 Bean 和工厂 Bean( FactoryBean )

    普通 Bean:在配置文件中定义的 Bean 类型就是返回的类型。

    工厂 Bean:在配置文件中定义的 Bean 类型可以和返回类型不一样。

  2. 工厂 Bean 的创建

    第一步:创建类,让这个类作为工厂 Bean,实现接口FactoryBean

    第二步:实现接口里面的方法,在实现的方法中可以定义返回对象的类型

    例如:
    public class MyBean implements FactoryBean<course> {
    //定义的是MyBean类型,返回的是course类型
        @Override
        public course getObject() throws Exception {
            course c = new course();
            return c;
        }
    }
    

IOC 操作 Bean 管理(Bean 作用域)

  1. 在 Spring 里面,设置创建 Bean 实例是单实例还是多实例,叫做Bean的作用域。(面试)

​ 在 Spring 里面,默认创建单实例对象(验证如下)。(面试)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-txYDcnrz-1649943729811)(…/AppData/Roaming/Typora/typora-user-images/image-20220414205344469.png)]

IOC 操作 Bean 管理(Bean 生命周期)

Bean 的生命周期

第一步:通过构造器创建 Bean 实例对象(无参构造)

第二步:为 Bean 的注入 属性值 或 外部引用 Bean (调用set方法或有参构造方法)

第三步:*把 Bean 实例传给 Bean 后置处理器方法

第四步:调用 Bean 的初始化的方法(需要配置初始化方法)

第五步:*把 Bean 实例传给 Bean 后置处理器方法

第六步:Bean 使用

第七步:手动 Bean 的销毁,当容器关闭的时候,调用 Bean 销毁方法(需要配置销毁方法)

//实体类
public class oders  {
    private String oname;

    public oders() {
        System.out.println("第一步:调用无参构造方法创建实例对象");
    }
    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步:通过set方法设置属性值");
    }
    //第三步:把 Bean 实例传给 Bean 后置处理器方法postProcessBeforeInitialization
    public  void init_oders(){
        System.out.println("第四步:调用初始化方法");
    }
    //第五步:把 Bean 实例传给 Bean 后置处理器方法postProcessAfterInitialization
    public void output(){
        System.out.println("第六步:使用Bean" +oname);
    }
    public void destroyMethod(){
        System.out.println("第七步:执行销毁方法");
    }
}
//后置处理器类
public class MyBean implements BeanPostProcessor {
}
    <bean name="order" class="src.com.dao.oders" init-method="init_oders" destroy-method="destroyMethod">
        <property name="oname" value="手机"></property>
    </bean>
<!--    配置Bean后置处理器-->
    <bean id="a1" class="src.com.dao.MyBean"></bean>
<!--    配置的这个后置处理器会默认把所有Bean都设置去执行 后置处理器方法-->
@Test//Bean生命周期测试
public void orderTest(){

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("src/com/oderBean.xml");
    oders obj = context.getBean("order",oders.class);
    //使用Bean
    obj.output();
    //手动销毁Bean
    context.close();
}

IOC 操作 Bean 管理(基于XML自动装配)

通过标签注入属性—手动装配

什么是自动装配:根据属性的 名称 或 类型 进行自动匹配注入

实现:

<!--    自动装配 autowire
                属性值:  byName 根据属性名称自动装配  注入Bean的id值 要与属性名称一致
                         bytype 根据类型自动注入-->
    <bean name="order" class="src.com.dao.oders" autowire="byName">
    </bean>
    <bean name="stu"></bean>

IOC 操作 Bean 管理(基于XML外部属性文件)

引入外部属性文件 例如下:

xml配置写法如下:

① 引入名空间 context

②如图

image-20220414205407511


IOC 操作 Bean 管理(***基于注解方式的 Bean 管理)

  • 什么是注解?

​ 注解是代码的特殊标记。

​ 格式:@注解名称(属性名称=属性值,属性名称=属性值)

​ 注解可作用在 类上面 方法上面 属性上面

​ 使用注解的目的:简化 XML 配置

  • Spring 针对Bean 管理中 创建对象提供了四个注解如下:

​ @Component(创建对象注解中的普通注解)

​ @Service (一般用在业务逻辑层service层)

​ @Controller (一般用在web层)

​ @Repository (一般用在dao层)

*上述四个注解功能一样,只是为了提高代码的可读性。

1.基于注解方式创建对象步骤

第一步:引入 Aop 依赖包

第二步:开启组件扫描

------------------包中类都进行扫描---------------------
<!--   开启组件扫描
            若扫描多个包: 逗号隔开  或  扫描上一级目录-->
    <context:component-scan base-package="src.com.service"></context:component-scan>
------------------包中类选择性扫描---------------------
<!--    示例1 use-default-filters="false"表示不在使用默认扫描 需要自己配置  context:include-filter哪些进行扫描(包含Service注解的)-->
    <context:component-scan base-package="src.com.service" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
<!--    示例2 excludefilter哪些不进行扫描-->
    <context:component-scan base-package="src.com.service" use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>

第三步:创建类

在注解里 value 值可以省略不写,系统默认设置为 类名首字母小写userService

@Service(value = "userService")  //对应XML方式的  <bean id="userService" class="...">
public class UserService {
    public void add(){
       System.out.println("这里是userService------------------");
    }
}
第四步测试类

2.基于注解方式属性注入

(1)@Autowired 根据属性类型 进行自动注入

@Service(value = "userService") //对应XML方式的  <bean id="userService" class="...">
public class UserService {
    @Autowired   //根据类型自动注入
    private UserDao userDao;
    public void add(){
        userDao.addUserById();
       System.out.println("这里是userService------------------");
    }
}

(2)@Qualifier 根据属性名称进行自动注入

  • 与@Autowired 配合使用
@Service(value = "userService") //对应XML方式的  <bean id="userService" class="...">
public class UserService {
    @Autowired   //根据类型自动注入
    @Qualifier(value = "userDao") //根据名称自动注入
    private UserDao userDao;
    public void add(){
        userDao.addUserById();
       System.out.println("这里是userService------------------");
    }
}

(3)@Resource可以根据属性类型也可以根据属性名称进行注入(不推荐用)

//@Resource  根据类型注入
@Resource(name = "userDao")//根据名称 注入
private UserDao userDao;

(4)@Value

@Value("abczhnga")
private String name;

3.完全注解开发

创建配置类 替代配置文件组件扫描设置

@Configuration   //配置类标识
@ComponentScan(basePackages = {"src.com.service" })
public class springConfig1 {

}
测试类:
@Test
public void TestuserService2(){
        ApplicationContext context = new AnnotationConfigApplicationContext(src.com.config.springConfig1.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
}

+++

四.AOP

什么是 Aop

(1)面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

(2)通俗描述:不通过修改源代码的方式,在主干功能里添加新功能

(3)使用登录例子说明 Aop

image-20220414205434018

Aop 的底层原理

1.Aop 底层使用动态代理

(1)有两种情况动态代理:

第一种:有接口的情况,使用 JDK 动态代理

  • 创建接口实现类的代理对象,增强类方法

第二种:没有接口的情况,使用 CGLIB 动态代理

五.JdbcTemplate

六.事务管理

七.spring5新特性

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奥男

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值