1、Spring

1.1 Spring 简介

  • 2002年,spring框架的前身出现:interface21框架
  • 2004年,在基于interface21框架上进行重新开发设计 发行了初代版本的spring1.0框架
  • Rod Johnson Spring Framework的创始人,著名作者 ;他是 悉尼大学音乐学位博士 而居然不是计算机!
  • Spring理念:使现有的技术更加容易使用

下载方式:

官网全版本地址:https://repo.spring.io/ui/native/release/org/springframework/spring/

maven方式:

maven导包推荐导 spring web mvc 的包

spring web mvc

spring jdbc的包

spring jdbc

maven导入这两个包后 会将我们需要的依赖包一起导入,就不用再一一去导入

1.2 Spring 优点

  • Spring是一个 免费且开源的 框架!
  • Spring是一个 轻量级、非入侵式 的框架 框架本身小,引入方便;使用Spring不会改变原来代码的情况
  • 控制反转(IOC)、面向切面编程(AOP) 十分重要 面试必问

1.3 Spring 组成

img

Spring Core(核心容器):Spring框架底层 提供框架的基本功能 Spring使用BeanFactory来产生和管理Bean 也就是工厂模式的实现 BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开

Spring Context(上下文):Spring Context是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能

Spring AOP(AOP面向切面编程):Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。

Spring DAO(JDBC模块和DAO模块):JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。

Spring ORM(对象实体映射):Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。

Spring Web(web模块):Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

Spring Web MVC(MVC模块):MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。

2、IOC(控制反转)

2.1 什么是IOC

控制反转的控制 就是程序控制权的意思,反转呢就是将控制权力反转、互换

比如:==一个程序员对程序有控制权,如果一个客户需要什么功能,程序员将程序修改好之后,提交给客户使用,这个控制权就是在程序员的手中==

==经过控制反转(IOC)后 ,客户可以根据自己的需要,来选择对应的功能或者模块,就不再需要程序员去进行修改程序,这个控制权就是在客户手中==

==这也就是所谓的 控制反转(IOC)==

2.2 实现方法实例

在代码中实现:

例如用户有需要普通数据查询和在Mysql中查询的两种数据源

Dao(Mapper)层:

UserMapper

package cn.mianju.dao;

public interface UserMapper {
    void getUser();
}

UserMapperImpl

package cn.mianju.dao;

public class UserMapperImpl implements UserMapper{
    @Override
    public void getUser() {
        System.out.println("This method in the UserMapperImpl");
    }
}

UserMysqlMapperImpl

package cn.mianju.dao;

public class UserMysqlMapperImpl implements UserMapper {

    @Override
    public void getUser() {
        System.out.println("This method in the User!Mysql!MapperImpl");
    }
}

service层:

UserService

package cn.mianju.service;

public interface UserService {
    void getUser();
}

*UserServiceImpl(主要的修改就在这部分)

package cn.mianju.service;

import cn.mianju.dao.UserMapper;
import cn.mianju.dao.UserMysqlMapperImpl;

public class UserServiceImpl implements UserService{
    private UserMapper userMapper;
//    private UserMapper userMapper = new UserMysqlMapperImpl();

    public void setUser(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public void getUser() {
        userMapper.getUser();
    }
}

首先是设立一个Mapper(dao)的查询接口 UserMapper 然后有两种方式查询,一种是普通方式,一种是Mysql方式 普通方式为 UserMapperImpl Mysql方式为 UserMysqlMapperImpl ;然后在service层调用Mapper层的查询方法 接口类:UserService 实现类: UserServiceImpl

在做 控制反转 之前呢,正常来说是在service实现类**(UserServiceImpl)**中去赋值需要调用的方式、类

private UserMapper userMapper = new UserMysqlMapperImpl();

但是如果这样每次客户需要换一种方式的话就需要修改源代码,这就违反了OOP(开闭原则) 所以说,可以在service实现类**(UserServiceImpl)中去定义个setting** 使其可以在运行中的时候set注入 来让用户自由选择,用户需要什么就把它set成什么

调用的时候就需要把它先转换成子类再转换回来,这样才可以调用子类的set方法 idea快捷键:Ctrl+alt+空格 可以用子类方法

public class MyTest {
    @Test
    public void t(){
        UserService userService = new UserServiceImpl();
//        ((UserServiceImpl) userService).setUser(new UserMapperImpl());//This method in the UserMapperImpl
        ((UserServiceImpl) userService).setUser(new UserMysqlMapperImpl());//This method in the User!Mysql!MapperImpl
        userService.getUser();
    }
}

2.3 IOC总结

控制反转loC(Inversion of Control)

是一种设计思想,DI(依赖注入)是实现loC的一种方法,也有人认为DI只是loC的另一种说法。

没有loC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。

在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection,DI)

1

示例图: 原本的程序控制权是在业务层上,也就是代码上,但是经过控制反转后,控制权就移交到了用户手上,用户可以自行去调用所需,更灵活

3、Spring 的 "HelloWorld"

现在来写一个“第一段Spring代码”

3.1 创建项目 导入依赖包

新建一个Maven项目

修改pom.xml文件,导入对应的包:

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.17</version>
        </dependency>
</dependencies>

3.2 编写配置文件和类

编写一个hello 实体类 设置一个属性:

package cn.mianju.pojo;

public class Hello {
    private String str;

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

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

然后在resources文件夹下新建一个xml配置文件(idea点击resources文件夹按alt+Ins可以生成)

xml

编写配置文件(applicationContext.xml)

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    使用spring来创建对象 , 在spring中 这些对象都称为bean-->
    <bean id="hello" class="cn.mianju.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>

</beans>

配置文件解析:

在原本的Java程序中:

//类型 变量名 = new 类型();
Hello hello = new Hello();

Spring的Bean:

<!--
id = 变量名
class = new的对象
property = 给对象中的一个属性赋值

在property中还有个值是 ref:引用Spring中创建好的对象 也就是引用配置文件中配置好的Bean类型
-->
<bean id="hello" class="cn.mianju.pojo.Hello">
        <property name="str" value="Spring"/>
</bean>

3.3 测试

去创建一个测试类,在Test下

import cn.mianju.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //获取spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Hello hello = (Hello) context.getBean("hello");//这里的hello指向的就是applicationContext.xml中的id = hello
        System.out.println(hello.getStr());
        //Spring
    }
}

ApplicationContext context = new ClassPathXmlApplicationContext("配置文件1","配置文件2");

这行语句是固定写法,可以读取一个配置文件也可以读取多个配置文件

Hello hello = (Hello) context.getBean("hello");

然后get到他们的Bean,在Spring中不需要声明对象,Bean就是Spring的对象

getBean的参数在Spring的配置文件中是需要注册的,参数就是Bean标签的id

System.out.println(hello.getStr());

调用Bean中的方法

3.4 小结

  • **问题1:**Hello对象是谁创建的?
    • Hello对象是由Spring创建的
  • **问题2:**Hello对象的属性是怎么设置的?
    • ​ Hello对象的属性是由Spring容器设置的,也就是在 applicationContext.xml 中设置的
  • **问题3:**Bean是什么,它的作用是什么?
    • Bean是由Spring创建的一个对象;开始是程序员或是说程序创建的对象,也就是new一个对象;但是经过Spring的 控制反转(Ioc)机制后,对象的创建全交由Spring来做

这个过程就叫做控制反转:

  • 控制:谁来控制对象的创建,传统应用是程序员/程序来控制对象的创建;而Spring对象是统一交由Spring创建
  • 反转:程序本身不创建对象,而变成被动的接受对象
  • 依赖注入:利用Set方法来进行注入

IOC是一种编程思想,由主动的编程变成被动的接收!

4、Spring的对象创建方式

4.1 对象创建时间

在spring框架中, 我们没有用到任何的new关键字来new对象,都是通过spring来帮我们创建的,那么spring是什么时候开始创建对象的呢?

做个测试:声明一个pojo user类

package cn.mianju.pojo;


public class User {
    private String name;

    public User() {
        System.out.println("no args");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

当对象创建时 就会调用它的无参构造器

applicationContext.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="cn.mianju.pojo.User">
        <property name="name" value="xf"/>
    </bean>

</beans>

然后写一个MyTest类来测试:

import cn.mianju.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    public static void main(String[] args) {
        //加载配置文件的时候就已经把配置文件中的类创建好了
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //no args

//        User user = (User) context.getBean("user");

    }
}

运行一遍我们可以看到,在加载配置文件的时候,就已经把配置文件中的类创建完成了

4.2 有参构造

那如果想要有参构造器的类去创建,用上面的方法会出现报错

Caused by: java.lang.NoSuchMethodException: cn.mianju.pojo.User.<init>()

也就是初始化失败,需要参数

这个时候怎么传参给构造器呢

有三种方法:

第一种:

<?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="cn.mianju.pojo.User">
<!--        <property name="name" value="xf"/>-->
        <constructor-arg index="0" value="xf"/>
        <!--通过下标位置来传入参数-->
    </bean>

</beans>

第二种: 这种方式不建议使用

<?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="cn.mianju.pojo.User">
<!--        <property name="name" value="xf"/>-->
<!--        <constructor-arg index="0" value="xf"/>-->
        <constructor-arg type="java.lang.String" value="xf"/>
        <!--通过类型匹配来传入参数 tips:基本类型可以直接用 但是引用类型必须用全类名-->
    </bean>

</beans>

第三种:

<?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="cn.mianju.pojo.User">
<!--        <property name="name" value="xf"/>-->
<!--        <constructor-arg index="0" value="xf"/>-->
<!--        <constructor-arg type="java.lang.String" value="xf"/>-->
        <constructor-arg name="name" value="xf"/>
        <!--根据参数名来传入参数-->
    </bean>

</beans>

但是如果要传入引用类型就需要用到ref

<?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="cn.mianju.pojo.User">
        <constructor-arg name="name" value="xf"/>
        <constructor-arg name="teacher" ref="teacher"/>
    </bean>
    
    
    <bean id="teacher" class="cn.mianju.pojo.Teacher">
        <constructor-arg name="name" value="myTeacher"/>
    </bean>
    <!--如果需要传入引用类型 需要先声明一个bean 然后传入这个bean的id-->
    
</beans>

首先 需要传入的类型如果是引用类型(非String)

那么我们需要先声明一个Bean来表述这个类或者说创建这个类

然后将这个Bean的id 传入ref的标签中<constructor-arg name="teacher" ref="teacher"/>

这样就可以传入一个引用类型

上一篇 下一篇