Java教程

Spring5

本文主要是介绍Spring5,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本笔记参考尚硅谷Spring框架视频教程(spring5源码级讲解)_哔哩哔哩_bilibili,相关资料链接:链接: https://pan.baidu.com/s/1BPdI_vDWW2M-1A0okF3Pww 提取码: 2333 or DS418 - Synology DiskStation (quickconnect.cn)

Spring概念

基本概念

1.Spring 是轻量级(体积小,jar包少)的开源的 JavaEE 框架

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

3.Spring 有两个核心部分:IOC 和 Aop
(1)IOC:控制反转,把创建对象过程交给 Spring 进行管理
(2)Aop:面向切面,不修改源代码进行功能增强

4.Spring 特点
(1)方便解耦,简化开发 (2)Aop 编程支持 (3)方便程序测试 (4)方便和其他框架进行整合 (5)方便进行事务操作 (6)降低 API 开发难度

入门案例

​ 写一个入门案例分为几个步骤:①引入jar包②写一个即将交个Spring的IOC容器托管的bean类③编写Spring的xml配置文件④测试由Spring IOC容器来创建对象而非自己new一个对象

一、引入jar包

​ 使用资料里的spring所需jar包-iod基本包,这里面包括了四个Spring的核心jar包以及一个commons-logging的日志包。

​ Spring5的组件图中,Core Container是我们现在比较需要的。

二、编写User类,类中只有一个add方法

package com.atguigu.spring5;
public class User {
    public void add(){
        System.out.println("add方法....");
    }
}

三、编写Spring5的xml配置文件,在src下创建一个Spring_configuration.xml文件,目前文件名可以随意,因为我们下面是通过按照文件名来读取配置文件的,不是spring自动读取

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置 User 对象创建-->
    <bean id="user" class="com.atguigu.spring5.User"></bean>
</beans>

四、测试由Spring IOC容器来创建对象而非自己new一个对象,在test包下编写test方法,使用@Test注释(相关的jar包需要自己导入一下,导入junit包)

@Test
public void testAdd(){
    //1.加载Spring配置文件,通过ApplicationContext来加载,在src包下可以直接写文件名
    //如果配置的xml在其他地方,则可以通过FileSystemXmlApplicationContext()来获取配置文件
    ApplicationContext context =
        new ClassPathXmlApplicationContext("Spring_configuration.xml");
    //2.获取配置创建的对象
    User user = context.getBean("user", User.class);
    System.out.println(user);
    user.add();
}

打印结果:

​ 可以看到,我们没有在任何地方new一个对象出来,但还是成功调用了add方法,这是因为由SpringIOC容器帮我们实现了。


​ 那我自己有个问题,如果User需要构造函数初始化,那么SpringIOC容器会怎么办呢?比如User类中有name属性,我可以get这个属性,但是并不是由我自己初始化,那么这个name属性的值为多少呢?

​ 下面我进行测试:

​ 1.若我把User类改造成如下,有构造函数,但是没有默认的构造函数

public class User {
    private String name;
    public void add(){
        System.out.println("add方法....");
    }
    public User(String name) {this.name = name;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
}

​ 则Spring会在ApplicationContext context =new ClassPathXmlApplicationContext("Spring_configuration.xml");这个步骤报错,原因就是没有默认的构造函数,Error creating bean with name 'user' defined in class path resource [Spring_configuration.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.atguigu.spring5.User]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.atguigu.spring5.User.()

​ 2.我把默认的构造函数加上,再进行测试,发现一切正常,只不过get的name值为null。而且可以观察得出,这与我第一次运行时SpringIOC容器创建的User类后面的@的数字是一致的。

​ 3.当我不在User类里定义任何构造方法时,运行也正常。

​ 4.我在User类中定义无参的构造方法,在构造方法里把name赋值为joker,这个时候运行测试时,得到的name就为joker了。


那么我自己回答我刚刚提出的问题:

​ SpringIOC会调用默认的构造方法来初始化对象,但是由java本身的特性所致,如果我在User类里只定义了显式的构造方法,那么默认的构造方法就会失效,这个时候运行就会报错,如果一个构造方法我也没有给的话,java会默认给一个无参的构造方法。IOC容器就会调用无参的构造方法来初始化对象,如果自己给了无参的构造方法,那么IOC就会调用自己给的无参构造方法。

IOC容器

概念

一、什么是IOC?

​ 答:(1)控制反转,把对象创建和对象之间的调用过程,交给 Spring进行管理。这里的调用过程可以举个简单的例子:

​ 比如User类里需要用到Person类里的方法,不使用Spring时,一般要在User类里new一个对象出来,才能调用Person类的方法,如果交给了IOC容器来管理的话,就不用这么麻烦了,全部由Spring来控制。

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

我们入门的案例就是使用了IOC,从而使得我们没有new任何一个对象也能成功调用方法。

二、底层原理

​ 1.xml解析:xml解析从而获得class属性值,就是class=后面的字符串,接着使用反射创建对象之后再强转返回即可。这有个好处,就是我们要修改加载的对应的类的话,只需要修改xml里面class后面的属性值即可,其他地方不用修改。

​ 2.工厂模式:可以参考设计模式里的,简而言之就是A想获得B类的对象,这个时候可以通过工厂类C来获得B对象,B对象的实例化全部由C类来实现。由第三方类来完成实例化的过程

​ 3.反射:xml的class属性值交给Class类,然后Class类通过forName方法来创建该类Class对象,然后再调用Class类中的newInstance()方法来实例化对象。

实现IOC的两个接口类

一、IOC思想基于 IOC容器完成,IOC容器底层就是对象工厂,而Spring 提供 IOC 容器实现两种方式:(两个接口)

1.BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用。( 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象)

2.ApplicationContext:BeanFactory 接口的子接口(所以入门案例中的ApplicationContext类换成BeanFactory也可以正常运行),提供更多更强大的功能,一般由开发人
员进行使用 ( 加载配置文件时候就会把在配置文件对象进行创建)。

​ 而ApplicationContext有两个实现类,入门案例中使用的实现类ClassPathXmlApplication就是通过src文件夹下的xml文件名读取配置的类,还有FileSystemXmlApplicationContext通过系统绝对路径来读取xml配置文件。

Bean管理

一、何为Bean?

​ Bean其实就是要交给Spring托管的类的一种统称。

二、具体什么是Bean管理

​ Bean管理主要包括两个事情:Spring创建对象以及创建对象后由Spring对创建的对象注入属性。目前Bean管理操作有两种方式,分别是基于xml配置文件实现的方式基于注解的方式

三、DI依赖注入本质上其实就是给这些Bean类注入属性的意思

基于xml配置文件的管理方式

​ 注意:xml注入是通过set方法来实现的!!

创建对象

​ xml中一行就可以创建一个对象。

<bean id="user" class="com.atguigu.spring5.User"></bean>

​ 1.这其中id表示创建的这个对象的标识符,可以是任意的,与类名可以毫无关系,之后要拿到这个对象就需要把这个id值传给ApplicationContext类的getBean方法,从而得到已经实例化好的对象。

​ 2.class属性是类的全路径,用于支出创建对象的这个类具体是哪个类。

​ 3.创建对象时,默认也是执行无参数构造方法完成对象创建。若没有默认的无参构造方法调用,则会报错(这种情况常出现于类中显式地定义了一个有参构造而使得默认的无参构造失效时)。

注入属性

​ 对象中有着一个一个的属性,那么由Spring的IOC容器托管的这些对象的属性值的赋值情况是怎样的呢?

如果我们没有注入属性,默认使用的无参构造,那么属性值就是null,如果我们注入了属性,那就是我们注入的属性值,那么注入属性有两种方式

使用set方法

​ 比如入门案例中的User类,有个类型为String的name属性值,并且设置set方法,那么我在xml文件里可以通过这种方式进行属性注入:

​ xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置 User 对象创建-->
    <bean id="user" class="com.atguigu.spring5.User">
        <property name="user_name" value="Lucy"/>
    </bean>
    <bean id="user2" class="com.atguigu.spring5.User">
        <property name="user_name" value="Joker"/>
    </bean>
</beans>

​ User类

package com.atguigu.spring5;
public class User {
    private String user_name;
    public void add(){
        System.out.println("add方法....");
    }
    public User() {}
    public User(String user_name) {this.user_name=user_name;}
    public String getUser_name() {return user_name;}
    public void setUser_name(String user_name) {this.user_name = user_name;}
}

​ 可以看到我在xml里,让IOC容器托管了两个User对象,不过name不一样,我们编写测试类来进行测试:

@Test
public void testAdd(){
    //1.加载Spring配置文件,通过ApplicationContext来加载,在src包下可以直接写文件名
    //如果配置的xml在其他地方,则可以通过FileSystemXmlApplicationContext()来获取配置文件
    ApplicationContext context =
        new ClassPathXmlApplicationContext("Spring_configuration.xml");
    //2.获取配置创建的对象
    User user1 = context.getBean("user", User.class);
    System.out.println(user1+",这个用户的名字为"+user1.getUser_name());
    User user2 = context.getBean("user2", User.class);
    System.out.println(user2+",这个用户的名字为"+user2.getUser_name());
}

使用有参构造

​ 可以看到我的User类中写了一个有参构造,我们也可以使用有参构造来实现DI。

    <bean id="user" class="com.atguigu.spring5.User">
        <constructor-arg name="user_name" value="Lucy"/>
    </bean>
    <bean id="user2" class="com.atguigu.spring5.User">
        <constructor-arg name="user_name" value="Joker"/>
    </bean>

注入其他属性

​ 刚刚我们给类中的属性注入的都是String类型,那如果我们想注入外部bean,和带特殊符号的String以及集合,该怎么办呢?

字面量

1.注入null

<bean id="user" class="com.atguigu.spring5.User">
    <property name="user_name" value="Lucy">
    	<null/>
    </property>
</bean>

2.当注入的String有特殊符号,比如尖括号<>这个时候可以使用一下方式来处理

<bean id="user" class="com.atguigu.spring5.User">
    <property name="user_name" value="$lt;Lucy$gt;"/>
    <!--就等于给user_name赋值<Lucy>-->
</bean>

​ 如果不想转义,可以将带特殊符号的内容写到CDATA中:

<bean id="user" class="com.atguigu.spring5.User">
    <constructor-arg name="user_name">
        <value><![CDATA[<Lucy>]]></value>
    </constructor-arg>
</bean>

注入外部bean

​ 比如现在有一个给User类加钱的类AddMoney,AddMoney类中聚合了User类,属性名为addmoney_user,这个时候User类就是AddMoney类的属性的类,这个时候注入时xml需要这么写:

public class AddMoney {
    private User addmoney_user;//AddMoney类
    public User getAddmoney_user() {return addmoney_user;}
    public void setAddmoney_user(User addmoney_user) {this.addmoney_user = addmoney_user;}
    public void add_money(){
        System.out.println("我是AddMoney类,我要给名为"+ addmoney_user.getUser_name()+"的用户加钱");
    }

​ xml写法:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.atguigu.spring5.User">
        <constructor-arg name="user_name">
            <value><![CDATA[<Lucy>]]></value>
        </constructor-arg>
    </bean>
    <bean id="addmoney1" class="com.atguigu.spring5.AddMoney">
        <!--注入User对象 
        name 属性:类里面属性名称 
        ref 属性:创建 userDao 对象 bean 标签 id 值 -->
        <property name="addmoney_user" ref="user"/>
    </bean>
</beans>

测试结果如下:

​ 那如果我不想额外创建标签,想现创建一个User对象的话可以这么写:

<bean id="addmoney1" class="com.atguigu.spring5.AddMoney">
    <property name="addmoney_user" >
        <!--  <bean id="user_in_addmoney1" class="com.atguigu.spring5.User">  -->
        <bean class="com.atguigu.spring5.User">
            <property name="user_name" value="joker"/>
        </bean>
    </property>
</bean>

​ 里面的property创建的User类,我给它id属性是,idea提示我id是多余的,果然不加id也可以运行,那么我加了id之后,我可以通过ApplicationContext来获取到这个addmoney1对象里的User对象吗?

​ 答案是不能,在bean1中被初始化的bean2无法通过id找到,所以写了id和没写没有区别,其实我们可以通过bean1来找到bean2。

事务管理

Spring5新特性

这篇关于Spring5的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!