Spring5笔记01

本文介绍了Spring框架的核心部分——IOC容器,详细讲解了Spring的基本概念、IOC的原理和实践,包括如何创建对象、注入属性。同时,文章还涵盖了JUnit测试的注意事项和常用注解,帮助读者更好地理解和使用Spring框架。
摘要由CSDN通过智能技术生成

大纲

  1. Spring基本概念

  2. IOC容器

  3. Aop

  4. JdbcTemplate

    (把JDBC做了封装,更方便的操作数据库)

  5. 事务管理

  6. Sprin5新特性

Spring概念

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

    我们用一个框架,得引入里面一些相关依赖(jar包)

    Spring里体积小,不需依赖其他的,可以独立进行使用

    框架:它能让我们的开发更方便,代码更简洁。解决企业应用开发的复杂性。

    Spring有两个核心部分:IOC与Aop

    1. IOC

      控制反转/反转控制

      把创建对象的过程交给Spring进行管理,(帮我们创建对象,进行对象实例化)不需要再用new的方式

    2. Aop

      面向切面

      想在一个程序中扩展加个功能

      在不修改源代码的情况下,进行功能添加或增强

  2. Spring特点

    • 方便解耦,简化开发(解耦合)

      用IOC之后可以将耦合性降低

    • Aop编程支持

      不改变源代码,可以增强它的功能

    • 方便程序测试

      不需要写完整过程,对Junit4支持🔺

      • 方便继承各种优秀框架

        可以单独用,也可以整合框架(Struts2``Hibernate```Mybatis等)

    • 降低API开发难度

      把很多东西做了封装,方便进行事务的管理(如封装JDBC)

    • Java源码中经典代码

入门案例

  1. 需要下载相关需要jar包(Spring5)    sping.io官网

    • GA稳定版;SNAPSHOT快照版
    • Artifact是Maven中一个概念
    • 下载地址Spring的所有版本
    • 解压放在了D:\Program Files\spring-5.2.6.RELEASE-dist路径下
  2. 创建普通Java工程

  3. 导入Spring5相关jar包(依赖)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iQXZTqaE-1666512849806)(https://raw.githubusercontent.com/Fanyup/cloudimg/master/img/ApplicationFrameHost_66LFxOTNA9.png)]

实现基本功能起码要core(4)

导入jar包(复制)->File–Project Structure–Module(模块)–➕添加依赖

  1. 开始写代码

    想用Spring方式创建一个对象

    创建一个普通类,在这个类创建一个普通方法

    package com.atguigu.spring5;
    
    public class User {
        public void add(){
            System.out.println("add方法");
        }
    }
    
    • 配置文件√

    • 注解√(两种方式都可以,先选方法1)

  2. 创建Spring配置文件,在配置文件中配置要创建的对象

    1. Spring配置文件使用xml格式

      <bean id="user" class="com.atguigu.spring5.User"></bean>
      </beans>
      
  3. 测试代码编写(实际项目应用中不会写到)

    package com.atguigu.spring5.testdemo;
    
    import com.atguigu.spring5.User;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestSpring5 {
    
        @Test
        public void testAdd(){
            //1.加载spring配置文件
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean1.xml");
            //因为配置文件在类路径src下所以调用ClassPath可以直接写它的名字
    
            //2.获取配置创建的对象,得到对象
            User user = context.getBean("user", User.class);
            //3.调用对象方法
            System.out.println(user);
            user.add();
        }
    }
    

出现的一个小问题:爆红异常原因:commons-logging(日志)版本导错,此处必须要1.1.1版本的

其中注意:测试注解@Test需导入Junit4包🔺(我猜应该是JDK自带的,因为可以直接导包,用来测试单元执行)

commons-logging-1.1.1.jar

成功执行,测试说明对象创建成功。打印了对象地址,并调用对象方法。

com.atguigu.spring5.User@27f723
add方法
JUnit补充

JUnit是单元测试框架

[参考W3C基本用法](JUnit - 基本用法_w3cschool)

注意事项
  • 测试方法必须使用 @Test 修饰
  • 测试方法必须使用 public void 进行修饰,不能带参数
  • 一般使用单元测试会新建一个 test 目录存放测试代码,在生产部署的时候只需要将 test 目录下代码删除即可
  • 测试代码的包应该和被测试代码包结构保持一致
  • 测试单元中的每个方法必须可以独立测试,方法间不能有任何依赖
  • 测试类一般使用 Test 作为类名的后缀
  • 测试方法使一般用 test 作为方法名的前缀
常用注解
  • @Test:将一个普通方法修饰成一个测试方法@Test(excepted=xx.class): xx.class 表示异常类,表示测试的方法抛出此异常时,认为是正常的测试通过的 @Test(timeout = 毫秒数) :测试方法执行时间是否符合预期

IOC容器

  1. IOC是什么?能做什么事?底层原理?

    不是一门技术,而是一种设计思想

  2. IOC接口(一个重要接口:BeanFactory)

  3. IOC具体操作

    什么是Bean管理?(基于xml或注解方式)

什么是IOC

控制反转/反转控制:(一种软件设计模式)

对象的控制权转移了,从开发人员转移到对象容器了!

其遵循软件工程重点依赖倒置原则;

依赖注入(DI,Dependency Injection)时Spring框架实现控制反转的一种方式。(注释)

把对象的创建和对象之间的调用过程,都交给Spring管理

解耦合(降低耦合度)

入门案例就是IOC实现

IOC底层原理
  1. xml解析

  2. 工厂模式

  3. 反射

举例

两个类,想在UserService类中调用UserDao中的方法

过去做法:

UserDao dao = new UserDao();创建实例对象

dao.add();调用方法

存在一个问题:耦合度太高了,关联过于紧密,不利于程序扩展。

解决方案:工厂模式–为了解耦合

注意,工厂模式并不是最终过程,而是演变过程,最终我们会用IOC实现。

  1. 建一个工厂类UserFactory创建一个方法(其实就是接口多实现)

  2. 该方法返回Dao类对象;

    class UserFactory{
        public static UserDao getDao(){
            return new UserDao();
    }
    }
    
  3. 此时UserService不需要再在类里直接new Dao对象

    而是调用工厂

    UserDao dao =UserFactory.getDao();
    dao.add();
    

新问题:工厂还是有耦合度

🔺Java实体书

最终目的:将耦合度降到最低限度——IOC

IOC解耦过程
  1. xml配置文件

    配置需要创建的对象(创建哪些对象?)

    <bean id="dao class="全类名"></bean>
    
  2. 有一个service类和dao类,想在service类中调用dao类。

    创建一个工厂类

    class UserFactory{
        public static UserDao getDao(){
            String classValue = class属性值;
    //xml解析获取类名
    //用反射和类名调用方法
    //dom4j是xml解析的一种
    //通过反射创捷对象,先得到类的字节码文件
            Class c = Class.forName(classValue;)
            return(UserDao)c.newInstance();//创建对象
    //return强转
    
    }
    }
    

注意,此时通过xml解析+反射方式

现在只需修改配置文件,其他地方不用动——解耦合!进一步降低耦合度

IOC(两个重要接口)

  1. IOC思想基于IOC容器完成,

  2. IOC容器底层是一个“对象工厂”

  3. Spring提供IOC容器实现的两种方式(两个重要的接口

    1. BeanFactory:IOC容器最基本实现方式,是Spring内部使用接口,一般不提供给我们开发人员使用。

      • 加载配置文件时,不会创建对象,

      • 而在获取(使用)对象时,它才去创建这个对象。

    2. ApplicationContextBeanFactory接口的子接口。提供更多、更强大的功能。一般面向开发人员进行使用。(常用)

      • 在加载配置文件时,就会把在配置文件中对象进行创建。

    功能相似

    他们都能实现加载配置文件,通过工厂过程去创建对象。

    把耗时耗资源的操作都在(交给)项目(服务器)启动时创建对象更好,而不是什么时候用什么时候启动,所以ApplicationContext接口更好

  4. ApplicationContext接口里的主要实现类:

    点击类➕Ctrl+H打开类的结构

ApplicationFrameHost_gkBPCUCpNh.png

ClassPath(类路径)

Bean管理

  1. 什么是Bean管理?

    指的是两个操作:

    1. Spring创建对象

    2. Spring注入属性

  2. Bean管理操作有两种实现方式:

    1. 基于xml配置文件方式实现

    2. 基于注解方式实现

1.基于xml方式创建对象
<bean id="dao class="com.atguigu.Spring5.User"></bean>

使用bean标签,在标签里添加对应属性,就可以实现对象创建。

Bean标签里有很多属性,最常用属性:

  • id属性

    获取对象的唯一标识

  • class属性

    创建对象所在类的全路径(含包)

  • name属性

    和id相比,可以加特殊符号。早期属性,为Structs1提供,现在很少用。

创建对象时,默认也是执行无参的构造方法。

若添加有参,此时报错。Caused by: java.lang.NoSuchMethodException: com.atguigu.spring5.User.<init>()

2.基于xml方式注入属性
2.1属性注入的两种基本方式
  1. DI:依赖注入

    就是注入属性,是Ioc中一种具体实现,就表示依赖注入。但需要在创建对象的基础之上完成。

示例

快捷键Alt+Fn+Insert直接生成set方法、构造函数等等

  1. (原始方式)(set方式或有参构造注入)

    package com.atguigu.spring5.testdemo;
    
    public class Book {
        public void setBname(String bname) {
            this.bname = bname;
        }
        private String bname;
    
        public static void main(String[] args) {
            Book book = new Book();
            book.setBname("abc");
        }
    }
    
  2. 在Spring配置文件配置对象的创建,再配置属性注入

    property属性set方法

    .xml配置文件下:

    <!--创建对象-->
        <bean id="book" class="com.atguigu.spring5.testdemo.Book">
            <!--set方法注入属性,通过对象方法注入属性,要写到标签里面-->
            <!--使用标签property完成属性注入-->
            <property name="bname"value="hi!"></property>
            <!--name是类里指定的属性名称,value是要注入的值-->
        </bean>
    

    set方式这里我们还可以作进一步简化

    不用property属性方式

    p名称空间注入

    可以简化配置方式(了解)(实际中用的并不多)

    1. 添加一个p名称空间在配置文件中

      xmlns:p=...p

    2. 进行属性注入,可以在bean标签里进行

      <bean...p:name="bname" value="hi!"></beans>

      用这种方法就不用写property属性了

    方式2(通过有参构造方式)

    在配置文件中进行配置

    constructor-arg属性

<!--创建对象-->
    <!--id:获取对象的唯一标识-->
    <bean id="orders" class="com.atguigu.spring5.Orders"></bean>

此时这样写会爆红,为什么呢?因为默认找无参构造方法,而我们定义了有参后,无参构造就没了。

(注:还可以使用<constructor-args index="1"><../>索引方式)

于是我们更改成:

<bean id="orders" class="com.atguigu.spring5.Orders">
        <constructor-arg name="oname" value="computer"></constructor-arg>
        <constructor-arg name="address" value="China"></constructor-arg>
    </bean>
  1. 测试一下@Test(具体实现)

    (首先原Orders类中给定义一个方法,能输出才能看到测试结果。)

     @Test
        public void testOrders(){
            //1.加载spring配置文件
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean1.xml");
            //因为配置文件在类路径src下所以调用ClassPath可以直接写它的名字
    
            //2.获取配置创建的对象,得到对象
            Orders orders = context.getBean("orders", Orders.class);
    
            //3.调用对象方法
            System.out.println(orders);
            orders.orderTest();
        }
    

    这里一开始出现了一个小问题:测试爆红;其原因写的是xml第14行写错了。查看发现是value与class属性定义直接少了一个空格。

2.2注入其他形式属性

对象形式…其他形式…

  1. 字面量

    设定使用的固定值(写死的)

    以下这两种情况该怎么做呢?:

    • null值

      向属性里面设置控制,可以用null标签做到:(不用写value属性)

      <property name="bname" >
                  </null>
      </property>
      
    • 属性值中包含特殊符号

      如我想在value赋值里加入<>这样的特殊符号,但此时property标签会报错,因为它把它当作一个标签来识别了。

      解决方式一:把特殊符号进行转义,用&lt;&gt;

      解决方式二:把特殊符号内容写到CDATE

      首先要注意,属性是可以分开写的,形式像这样:

      <property name="bname" >
                  <value></value>
              </property>
      
    • 接下来,我们可以这样写:

       <property name="bname" >
                  <value><![CDATA[<<南京>>]]]]>
                  </value>
              </property>
      

      ![CDATE[...]]

      此时测试时会输出我们要的内容:<<南京>>

2.2.1.注入外部bean

举例演示:web层-service层-Dao层

演示过程:

  1. 创建两个类:Service类和Dao类

  2. 在Service调用Dao里面的方法

    通过xml配置方式完成

    接口:

    package com.atguigu.spring5.dao;
    
    public interface UserDao {
        public void update();
    }
    

    接口实现类:快捷键alt+Fn+enter重写接口方法

package com.atguigu.spring5.dao;

public class UserDaoImpl implements UserDao{

    @Override
    public void update() {
        System.out.println("dao的update方法");
    }
}

通过UserService中调用UserDao(原始方式)(但我们这里

public class UserService {

    public void add(){
        System.out.println("service add...");
        //原始方式
        //创建UserDao对象
        UserDao user = new UserDaoImpl();
        //多态
        user.update();
    }
}

用Spring方式实现

在spring配置文件中进行配置

  1. 把userdao注入到userservice中就可以(set方法或有参构造)现在注入属性对象类型

    通过生成set方法完成注入(快捷键alt+Fn+Insert

    public class UserService {
    
        //创建UserDao类型属性(对象类型),生成对应set方法
        private UserDao userDao;
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        public void add(){
            System.out.println("service add...");
            userDao.update();
        }
    }
    

    注意:二周目我在这里做了一个测试:将set方法去掉再进行测试会怎样?结果是爆红!

    我理解这里的含义是:首先创建一个UserDao类的对象类型,此时需要通过创建Setter方法,将此时的形参对象指向UserDao类的当前对象这个对象;(因为this本身作用就是指向当前对象),这样就将UserService类中创建的这个对象类型属性,成功指向userDao类中对象了。(即将UserDao类的实例成功注入到UserService类中),这样就可以调用UserDao类中方法了。

  2. 配置文件中进行配置(在配置文件中把两个类的对象创建)

 <!--创建service和dao对象-->
    <!--id名可以随便起,但作用是唯一指向-->
    <bean id="userService" class="com.atguigu.spring5.service.UserService">
        <!--注入userDao对象-->
        <!--name是类里面的属性名称,这里指上文对象类型属性名称-->
        <!--因为注入的是对象,所以此时不写value,而是ref-->
        <!--ref属性:指向创建的实现类对象的bean标签的id值(唯一)-->
        <!--ref就完成了外部bean注入,注入了其他对象-->
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>
    <bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>

ref即为reference,有“引文,引证,参考,参照”之意。

  1. 测试效果(import org.junit.Test;
public class testBean {
    @Test
    public void testAdd(){
        //1.加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        //2.获取配置创建的对象
        UserService userService = context.getBean("userService",UserService.class);
        userService.add();//因为我们将add方法里调用了UserDao类实例的update方法
    }

成功输出:

service add...
dao的update方法
2.2.2注入内部bean和级联赋值
  1. 一对多关系:典型关系:部门和员工

    一个部门里有多个员工,一个员工属于一个部门

    部门是一,员工是多

    我们要在实体类之间表示一对多的关系

//员工类
public class Emp {
    private String ename;
    private String gender;
    //员工属于某一个部门,使用对象形式进行标识
    //表示员工所属的部门(对象类型属性)
    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
}
//部门类
public class Dept {
    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }
}
  1. 写spring配置文件,通过配置文件,完成内部bean的操作。向里面注入属性。
    <!--内部bean-->
    <!--创建员工类实例对象-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <!--设置属性(3个)普通基本属性和对象属性-->
        <property name="ename" value="Jack"></property>
        <property name="gender" value=""></property>
        <!--对象类型属性-->
        <property name="dept" 【这里该如何写?】
    </bean>

此时设置对象类型属性有两种方法

  1. 用刚刚我们学的外部bean方式:

    在xml中创建一个部门类的对象,用ref将其引入

  2. 这里我们用内部bean写法

    嵌套:在里面把dept的对象创建出来

    再在这里面设置属性值(一个部门总得有个名儿吧!上面的UserDao为什么不用呢,因为这里是两个不同的案例)

    在一个bean里面可以嵌套另一个对象

     <!--内部bean-->
        <!--创建员工类实例对象-->
        <bean id="emp" class="com.atguigu.spring5.bean.Emp">
            <!--设置属性(3个)普通基本属性和对象属性-->
            <property name="ename" value="Jack"></property>
            <property name="gender" value=""></property>
            <!--对象类型属性-->
            <property name="dept">
                <bean id="dept" class="com.atguigu.spring5.bean.Dept">
                    <property name="dname" value="安保部"></property>
                </bean>
            </property>
        </bean>
    

但实际中还是很多人喜欢用外部bean,因为这样更清晰;

  1. 测试一下:

    在员工类中加一个add()方法,显示输出值,证明调用成功

    为了显示对象的值,我们再部门类中重写一下toString方法

     @Override
        public String toString() {
            return "Dept{" +
                    "dname='" + dname + '\'' +
                    '}';
        }
    

快捷键Alt+Fn+Insert

这里想提一点,因为toString是Object类的方法,所以会默认调用。我们在这里重写了它,这样输出dname时即会根据重写方法输出dname的值;如果这里我们不重写toString方法,得到的结果会是:

Jack男com.atguigu.spring5.bean.Dept@7403c468即dname的内存地址。因为dname是实例对象,我们在xml文件中为dept对象的属性dname赋了一个值。该例与userDao类不同的区别是,上文类只有方法而没有成员属性。如果有,也是一样的用法的。

 @Test
    public void testBean2(){
        //1.加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");

        //2.获取配置创建的对象
        Emp emp = context.getBean("emp",Emp.class);
        emp.add();
    }

成功获得结果

Jack男Dept{dname='安保部'}

刚才的过程其实就是一种级联赋值

级联赋值还有其他写法

2.2.3级联赋值
  1. 方法一:外部bean方式引入

        <!--级联赋值-->
        <!--内部bean-->
        <!--创建员工类实例对象-->
        <bean id="emp" class="com.atguigu.spring5.bean.Emp">
            <!--设置属性(3个)普通基本属性和对象属性-->
            <property name="ename" value="Jack"></property>
            <property name="gender" value=""></property>
            <!--对象类型属性-->
            <!--级联赋值-->
            <property name="dept" ref="dept"></property>
    
        </bean>
        <bean id="dept" class="com.atguigu.spring5.bean.Dept">
            <property name="dname" value="财务部"></property>
        </bean>
    </beans>
    

重新测试一下:成功

  1. 方法二:

复盘后对于方式二我是这样理解的:上面都是通过创建部门类的对象的方式注入dname属性的值,所以员工部只需要dept对象的set方法就好了,即指向它。而这种形式则不通过此,而是直接在员工部的dept对象中修改,注入dname属性。那么此时会遇到一个问题,就是我们用set方法只能指向而不能返回,即修改值,这是就需要get方法来return dept返回对象类型,通过对象类型的牵引找到dname。(结论:为了能找到dname)

 <!--对象类型属性-->
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
        <property name="dept.dname" value="技术部"></property>

dept.dname:向dept的对象属性中设置dname的值(对象类型属性名.成员属性)

但是报错了,为什么?

因为我们需要向员工类中的dept对象类型属性中的dame设置值,但我们没有得到对象,所以我们需要生成dept的get方法

在员工部修改如下:(添加入get方法)

 private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

修改后xml如下:

    <!--级联赋值-->
    <!--内部bean-->
    <!--创建员工类实例对象-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <!--设置属性(3个)普通基本属性和对象属性-->
        <property name="ename" value="Jack"></property>
        <property name="gender" value=""></property>
        <!--对象类型属性-->
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
        <property name="dept.dname" value="技术部"></property>

    </bean>
    <bean id="dept" class="com.atguigu.spring5.bean.Dept">
        <!--此时这句可要可不要,因为最终会被上面覆盖,所以可以删去-->
        <property name="dname" value="财务部"></property>
    </bean>

我们需要生成dept的get方法

在员工部修改如下:(添加入get方法)

 private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

修改后xml如下:

    <!--级联赋值-->
    <!--内部bean-->
    <!--创建员工类实例对象-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <!--设置属性(3个)普通基本属性和对象属性-->
        <property name="ename" value="Jack"></property>
        <property name="gender" value=""></property>
        <!--对象类型属性-->
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
        <property name="dept.dname" value="技术部"></property>

    </bean>
    <bean id="dept" class="com.atguigu.spring5.bean.Dept">
        <!--此时这句可要可不要,因为最终会被上面覆盖,所以可以删去-->
        <property name="dname" value="财务部"></property>
    </bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值