初识Spring

目录

1、什么是Spring

2、Spring环境搭建

2.1、依赖导入

2.2、文件配置

3、了解IOC

3.1、什么是IOC?

3.2、初识IOC

3.3、HelloSpring

3.4、使用Spring

4、IOC对象创建的几种方式

4.1、使用无参构造(默认)

4.2、使用有参构造

4.3、对象何时创建

5、Spring配置

5.1、Import

5.2、Bean和Beans

5.3、alias

6、依赖注入(DI)

容器注入

set注入

拓展注入

7、Bean的作用域

7.1、singleton 单例 (Spring默认)

7.2、prototype 原型

7.3、session、request、application

8、Bean的自动装配(自动注入)

8.1、Byname

8.2、Bytype

8.3、使用注解

8.4、小结

9、使用注解开发

9.1、Bean的实现

9.2、属性注入

9.3、自动装配

9.4、衍生注解

9.5、小结


1、什么是Spring

  • Spring:春天 也就是软件行业的春天 设计之初的目的是为了简化企业级的应用开发过程

  • 历史:2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。

    2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版

  • 优点

    1、Spring是一个开源免费的框架 , 容器 .

    2、Spring是一个轻量级的框架 , 非侵入式的 .

    3、控制反转 IoC , 面向切面 Aop(核心)

    4、对事物的支持 , 对框架的支持

一句话概括

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

2、Spring环境搭建

2.1、依赖导入

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

这个依赖里面包含了我们所要用的大部分依赖 ,我们学习Spring也就需要8个依赖 而这个就已经包含了6个 足以应对我们前期的学习

依赖导入完成之后 就是编写配置文件了 Spring和maven一样 都是一个约束大于配置的工具

2.2、文件配置

在resources文件目录下 创建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=""     class="">
        <property name="" ref=""></property>
    </bean>
    
    <bean id=""     class="">
        <property name="" value=""></property>
    </bean>
    <!-- more bean definitions go here -->
​
</beans>

这里面的id使我们将来获取bean的变量名 class是我们需要配置的对应的实体类的绝对地址

如果这个类中有变量 或者返回值我们就用<property>这个标签

如果这个类中需要配置的是一个简单变量 我们用value给这个bean赋值

如果这个类中需要配置的是一个类引用 我们用ref来指向我们需要引用的这个类

3、了解IOC

3.1、什么是IOC?

IOC(Inversion of Control)中文意思 控制反转 通俗的讲就是 控制权的准换

以前的开发 控制权在开发人员手上 用户需要什么需要 开发人员就得按照需求 修改大量的底层源码 从前台响应servlet到service层再到Dao层 牵一发而动全身

3.2、初识IOC

举个例子

我们有一个Dao层 一个Service层 一个Servlet(用test来模拟Servlet)它的大致结构是这样的

Dao层

public interface UserDao {
     void getuser();
}
​
​
public class UserDaoImpl implements UserDao {
    public void getuser() {
        System.out.println("正在获取用户");
    }
}
​
​
public class UserMysqlImpl implements UserDao{
    public void getuser() {
        System.out.println("正在获取Mysql");
    }
}
​

Service层

public interface UserServcie {
    void getUser();
}
​
public class UserServiceImpl implements UserServcie{
  //调用userdaoImlp
    private UserDao userDao=new UserDaoImpl();
​
  //调用userMysqlImpl
     private UserDao userDao1=new UserMysqlImpl();
 //DaoImpl方法实现
    public void getUser() {
        userDao.getuser();
    }
 //MysqlImpl方法实现
    public void getUser1() {
         userDao1.getUser()
    }
    
}

Servlet层(Test模拟)

public class UserTest {
​
    @Test
    public void get(){
      UserServcie userServcie=new UserServiceImpl();
     //调用DaoImpl
        userServcie.getUser();
     //调用MysqlImpl
        userServcie.getUser1();
    }

从上面的例子我们可以看出 如果这是我们多了一个新的实现类 我们需要从头改到尾 假设我们有100个、1000个这样的需求 那我们的工作量可想而知

于是我们开始考虑优化 我们可以在Service层的实现类中设置一个接口 使用Set方法 构造一个函数 使得每次servlet调用Service层时 只需要将需要引用的类作为参数输入就行 根据这种想法 我们有了下面这种思路

Service层

public class UserServiceImpl implements UserServcie{
   private UserDao userDao;
​
        public void setUserDao (UserDao userDao) {
        this.userDao = userDao;
    }
​
    public void getUser() {
        userDao.getuser();
​
    }
}
​

Servlet层(Test模拟)

public class UserTest {
​
    @Test
    public void get(){
      UserServcie userServcie=new UserServiceImpl();
      ((UserServiceImpl) userServcie).setUserDao( new  UserMysqlImpl());
      userServcie.getUser();
    }
   

new UserMysqlImpl() 就是我们需要引用的方法 我们现在只需要在这里输入就行了 无需改动Service层

这就是一个控制反转的典型例子 刚开始 我们通过把程序写死的方式 得到了一个完整的程序 但是后期的维护 、更新 代价太大 我们完全依靠程序自身创建 运行,改动过后 程序变得单纯许多 它只负责运行 至于运行的内容是什么 都有我们在Servlet层进行传递 也就直说控制权由程序自身 转到了我们身上

3.3、HelloSpring

接下来 我们使用Spring来使我们的程序变得更轻巧

首先 编写一个简单的HelloSpring‘来验证我们的环境是否搭建成功

创建实体类

public class Hello {
    private String hello;
​
    public Hello(String hello) {
        this.hello = hello;
    }
​
    public Hello() {
    }
​
    public String getHello() {
        return hello;
    }
​
    public void setHello(String hello) {
        this.hello = hello;
    }
​
    @Override
    public String toString() {
        return "Hello{" +
                "hello='" + hello + '\'' +
                '}';
    }
}
​

编写配置文件ApplicationContext

<?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="hello" class="com.llf.Pojo.Hello">
    <property name="hello" value="Spring">
​
    </property>
</bean>
​
</beans>

这些文件可以直接从官网上copy 千万不要手敲

配置完之后 你的配置文件旁边就会多了一个绿色的小叶子

这样就表示你的实体类与Spring配置完成了

如果没有小叶子 我们可以在Idea插件中心下载安装spring assistant插件 类中就有小叶子的提示了

第一种

File-->Settings-->plugins-->搜索 spring assistant-->Inall

第二种

File-->Settings-->Project Structure-->Modules-->选择自己程序、点击右边的加号 添加

然后编写测试类

public class HelloTest {
    @Test
    public void get(){
    ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        System.out.println(context.getBean("hello").toString());
    }
}

new ClassPathXmlApplicationContext(" ")这里来填入我们的xml配置文件进行资源加载,可以填入多个xml文件 我们可以输入new CPX来让Idea提示 得到它

这里我们发现返回的是ApplicationContext,而不是ClassPathXmlApplicationContext,通过查看源码我们知道ClassPathXmlApplicationContext进行了多次的继承 而最终的父类是ApplicationContext 因此可以返回ApplicationContext

输出运行

由此可见我们的环境已经搭建成功

接下来返回我们之前的例子 使用SPring来实现它

3.4、使用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">
    <bean id="userDaoImpl" class="com.llf.Dao.UserDaoImpl"></bean>
    <bean id="userMysql" class="com.llf.Dao.UserMysqlImpl"></bean>
    <bean id="UserService" class="com.llf.Service.UserServiceImpl">
        <property name="userDao" ref="userMysql"></property>
    </bean>
​
</beans>

接下来就是在Test中加载xml文件 并运行

​
public class UserTest {
    @Test
    public void get1(){
       ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        UserServcie userServcie = (UserServcie) context.getBean("UserService");
        userServcie.getUser();
​
    }
​
}

而如果我们需要调用DaoImpl方法 只需要在xml文件中修改即可

    <bean id="UserService" class="com.llf.Service.UserServiceImpl">
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>

比我们之前的方法更加简单 代码更易于实现 即使是外行 也可以仅仅在xml文件中修改参数来实现不同的效果

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

4、IOC对象创建的几种方式

4.1、使用无参构造(默认)

这是默认的创建方式 但前提时必须要有无参函数 否则就会报错

    <bean id="User" class="com.llf.Pojo.User">
    </bean>

4.2、使用有参构造

  • 通过实体类参数下标创建对象

        <bean id="User1" class="com.llf.Pojo.User">
        <constructor-arg index="0" value="llf1"></constructor-arg>
        </bean>

  • 通过参数类型创建对象 若多个参数的参数类型一致 会产生歧义 (不推荐使用)

       <bean id="User2" class="com.llf.Pojo.User">
            <constructor-arg type="java.lang.String" value="llf2"></constructor-arg>
        </bean>

    type:参数类型 基本类型的参数可以写简称 引用类型必须写全称

  • 通过参数名来创建对象 (推荐)

    <bean id="User3" class="com.llf.Pojo.User">
        <constructor-arg name="name" value="llf3"></constructor-arg>
    </bean>

4.3、对象何时创建

对象在我们加载ApplicationContext.xml文件的时候就已经创建成功了,而且是将xml配置中的所有Bean的对象都已经创建,我们需要的时候直接从Context容器中拿即可

举例:

我们可以发现 我们在执行HelloTest的时候 User的无参构造也被加载了进来 这说明User对象已经被创建了 但这绝对不是缓存

5、Spring配置

5.1、Import

import:文件导入合并 用于多人开发时 将其他人的ApplicationContext.xml文件进行合并引用 对于相同id 相同内容 也会进行合并

 <import resource="ApplicationContext1.xml"></import>

5.2、Bean和Beans

  <bean id="User4" class="com.llf.Pojo.User" name="userT userTT,USER;userTTT">
        <constructor-arg index="0" value="llf1"></constructor-arg>
    </bean>

id:bean的唯一标识符 class: bean对应的实体类 必须全限命名 包名+类名 name:起别名 它可以起多个别名 中间可以用空格、逗号、分号来进行分割 起别名后,原来的名字也可以访问

Beans:一个Beans可以由多个Bean组成,使用Beans标签将创建的Bean包裹

5.3、alias

alias:起别名

<alias name="hello" alias="Helll"></alias>

不同于name的是 它只能是一对一的关系 且不能在一个标签中有多个名字

6、依赖注入(DI)

依赖注入(Dependency import)DI

依赖注入的方式有容器注入、set注入(重点)、拓展注入

容器注入

所谓的容器注入其实就是构造器注入 即有参构造注入( <constructor-arg /> )

 <bean id="User1" class="com.llf.Pojo.User">
    <constructor-arg index="0" value="llf1"></constructor-arg>
    </bean>

set注入

    <!--Bean注入-->
    <bean id="address" class="com.llf.Pojo.Address">
        <property name="address" value="河南省洛阳市"></property>
    </bean>
    <!--普通注入-->
<bean id="student" class="com.llf.Pojo.Student">
    <property name="name" value="小杨"></property>
    <property name="address" ref="address"></property>
    <!--数组注入-->
    <property name="books">
            <array>
                <value>三国演义</value>
                <value>红楼梦</value>
                <value>水浒传</value>
                <value>西游记</value>
            </array>
    </property>
    <!--List-->
    <property name="hobbys">
            <list>
                <value>篮球</value>
                <value>听歌</value>
            </list>
    </property>
    <!--Map注入-->
    <property name="card">
            <map>
                <entry key="身份证" value="410325199812014012"></entry>
            </map>
    </property>
    <!--Set注入-->
    <property name="games">
         <set>
             <value>LOL</value>
             <value>DNF</value>
         </set>
    </property>
    <!--空值注入-->
    <property name="wife">
            <null/>
        </property>
    <!--Properties注入-->
    <property name="info">
            <props>
                <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/mydb1?serverTimezone=UTC</prop>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
    </property>
    </bean>

其中最基本的注入是 Bean注入和普通注入 其他注入都是关键词标签里面嵌套 value标签

拓展注入

c命名空间和p命名空间

    <!--c标签注入 本质是容器注入 需要有参方法-->
​
    <bean id="teacher" class="com.llf.Pojo.Teacher" c:name="李老师" c:age="18"/>
    <!--p标签注入 还是普通注入的方式-->
​
    <bean id="teacher1" class="com.llf.Pojo.Teacher" p:name="王老师" p:age="20"/>

使用c标签和P标签 都需要引入外部配置

        xmlns:c="http://www.springframework.org/schema/c"
​
        xmlns:p="http://www.springframework.org/schema/p"

两个外部配置的区别就只是开头和结尾的C、P的区别

7、Bean的作用域

7.1、singleton 单例 (Spring默认)

单例就是单一实例,相同的Bean的id 无论被取值多少次 它的对象只会被创建一次

将teacher这个id取值两次 然后输出这两次的hashcode() 是相等的 而且两者做==判断 也是true 证明它就是单例模式 由于是Spring默认的作用域 所以不需要在xml中额外配置

7.2、prototype 原型

和单例模式相反,它的含义是 每一次对相同bean的id进行取值时 都会创建一个新的对象

 <bean id="teacher" class="com.llf.Pojo.Teacher" c:name="李老师" c:age="18" scope="prototype"/>

        

通过观察我们可以知道 两次的取值 它分别对应两个不同的hashcode() 说明这个对象被创建了两次 也就是我们在java实体类中的操作一样 new了两次

7.3、session、request、application

这三个只能在java-web的开发中中使用

session:对象被存放在session中 页面关闭失效 也可以自己设置失效时间

requset:对象只在一次请求中有效

application: 全局有效 从服务器开启到服务器关闭的这段时间 也就是服务器一运行就产生 一关闭 就失效

8、Bean的自动装配(自动注入)

Bean自动装配有三种方式 Byname、Bytype、使用注解

8.1、Byname

<bean id="cat" class="com.llf.Pojo.Cat"/>
<bean id="dog" class="com.llf.Pojo.Dog"/>
<bean id="people" class="com.llf.Pojo.People" autowire="byName"/>

8.2、Bytype

 <bean id="people1" class="com.llf.Pojo.People" autowire="byType">
        <property name="name" value="小许"></property>
    </bean>

关键字:autowire 它有Byname、Bytype

8.3、使用注解

使用注解前我们需要引入配置文件

<!--配置文件 注意它和Spring配置文件的区别 我们只需要将spring换成context-->
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
    <!--开启自动装配-->
  <context:annotation-config/>
public class People {
    @Autowired
    @Qualifier (value="dog")
    private Dog dog;
    @Autowired
    @Qualifier (value="cat")
    private Cat cat;
    @Nullable
    private String name;

使用注解开发 我们只需要在bean的id对应的类的属性上添加@Autowired即可

@Nullable 字段标记这个注解 说明字段可以为空值

如果xml文件中 同一个类有多个Bean的id 我们可以指定类中的属性为某一个Bean的id所装配

    <bean id="dog" class="com.llf.Pojo.Dog"/>
    <bean id="dog111" class="com.llf.Pojo.Dog"/>
    <bean id="1" class="com.llf.Pojo.Dog"/>   
    <bean id="dg1" class="com.llf.Pojo.Dog"/>
​

就像这种情况 我们可以在dog属性上面添加@Qualifier (value="dog") 它是不可以单独使用的

另外 我们也可以用java自带的 @Resource 注解来实现

public class People {
  @Resource
  private Dog dog;
 @Resource
  private Cat cat;
  private String name;
}

8.4、小结

  • 使用Byname 必须保证Bean的id唯一并且类的构造方法中有该id关键字的构造方法

    比如 id为dog 那么类的构造方法中就必须得用setDog()方法

  • 使用Bytype 优点:可以不用配置Bean的id 它会自动按照class的类对应的属性进行装配

    缺点:但是他不适用于多个对象指向同一个class

    由于我们配置了两个beanID并指向了同一个类 所以它就直接报错了 当我们随便删除一个beanID它就恢复正常了

  • @Autowired与@Resource

    相同点:都是用来装配Bean的方法 都可以写在字段上或setter()方法上

    不同点:@Autowired 通过bytype实现 然后byname 且必须要求对象存在

    @Resource 先通过byname 然后bytype 最后才会报空指针异常

9、使用注解开发

9.1、Bean的实现

在之前的开发中 都是在xml文件中使用bean标签来注册bean 现在我们使用注解来实现

首先需要在配置文件中扫描包配置的注解 使xml文件可以得到它

 <!--扫描配置包下的注解-->
        <context:component-scan base-package="com.llf.Pojo"></context:component-scan>

然后在实体类中使用注解

@Component
public class User {
    
}

@Componment的作用就等同于 <bean id="user" class="com.llf.Pojo.User"/>

使用@Componment注册Bean以后 Bean的id 默认为类名 且首字母小写

测试

9.2、属性注入

之前我们在xml文件中使用<property name="name" value="lili"></property>这样的方式赋值

现在我们可以使用注解@Value来实现,这种情况下 我们可以不用创建set()方法

    @Value("lili")
    /** 作用类似于这句话
    <property name="name" value="lili"></property>
     **/
    private String name;

测试

9.3、自动装配

使用@Autowired与@Resource 来实现自动装配

也就是对引用值进行自动匹配

9.4、衍生注解

通过使用@Componment为了配合开发 我们又衍生出了不同层所用的不同注解 不过他们的功能相同 都是注册Bean

  • @Controller:web层

  • @Service:service层

  • @Repository:dao层

9.5、小结

xml与注解的区别

xml可以适用于任何场合 且修改方便 只是代码量相对较多

注解适用于常规的情况下 且代码量相对较少 只是后期维护修改困难

于是我们可是综合使用 在xml中注册Bean 然后用注解@Value来为属性赋值 用@Autowired实现自动装配

这样就不用在xml中扫描包了 扫描包只是为了加载类上的注解即@Componment

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值