Spring入门及IOC

15 篇文章 0 订阅
5 篇文章 0 订阅

Spring简介

Spring 意为 春天,指的是给软件行业带来春天。在2002 年,首次推出了Spring框架的雏形interface21框架。Spring框架以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。

Spring 是个Java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。

Spring 框架目标是:简化Java企业级应用开发,并通过pojo为基础的编程模型促进良好的编程习惯。

Spring理念是:使现有的技术更加容易使用,它整合了现有的技术框架。

有关Spring的网址:

官网:https://spring.io/projects/spring-framework#overview

官方下载地址: http://repo.spring.io/release/org/springframework/spring

GitHub:https://github.com/spring-projects/spring-framework

Spring的依赖:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

Spring的优点:

  • Spring是一个开源的免费的框架(容器),支持事务的处理,支持框架整合。
  • Spring是一个轻量级的、非入侵式的框架,基本的版本大约2MB。
  • 控制反转(IOC),Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
  • 面向切面编程(AOP),Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
  • 容器,Spring 包含并管理应用中对象的生命周期和配置。
  • MVC框架,Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
  • 事务管理,Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务。
  • 异常处理,Spring 提供方便的API把具体技术相关的异常转化为一致的unchecked 异常。

Spring就是一个轻量级的控制反转(IOC) 和面向切面编程(AOP)的框架

Spring的组成:

IOC

IOC思想

搭建环境并测试:

  1. 编写User实体类
  2. 编写UserMapper接口
  3. 编写UserMapperImpl实现类
  4. 编写UserService业务接口
  5. 编写UserServiceImpl 业务实现类
  6. 编写测试类

在业务中,用户的需求可能会发生改变,此时我们的代码就需要对应地进行修改。如果程序的代码量很大的话,修改一次的成本代价则会什么昂贵。

在业务层处理时,是由程序员创建对象的,可以说主动权在程序员手中,程序员决定了程序调用什么。

但是当使用一个set方法时,会发生革命性的变化。

利用set可以动态地实现值的注入。

对比:

  • 没使用set之前,程序是主动创建对象,控制权掌握在程序员手中。
  • 使用set注入后,程序不再具有主动性,而是被动地接受对象。

动态的注入这种思想,从本质上解决了问题,我们不用管对象的创建了,同时系统的耦合性大大降低了。我们可以更加专注地在业务的实现上,这就是IOC 的原型。

IOC本质

IOC(Inverse of Control),控制反转,是一种设计思想;DI(Dependency Injection),依赖注入则是显示IOC的一种方法。在没有IOC的程序中,我们使用面向对象编程,对象的创建和对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后则将对象的创建转移给第三方,所谓控制反转可以理解为:获得依赖对象的方式反转了。

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

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

第一个Spring程序

1. 导入Spring相关的jar包

Spring需要导入commons-logging进行日志记录 。我们使用maven , 他会自动下载对应的依赖项。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.10.RELEASE</version>
</dependency>

2. 编写相关的代码

编写一个Hello实体类

package com.llx.pojo;

public class Hello {
    private String name;

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

    public void show(){
        System.out.println("Hello,"+name);
    }
}

编写我们的Spring文件,将其命名为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
        https://www.springframework.org/schema/beans/spring-beans.xsd ">

    <bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>

</beans>

测试

@Test
    public void testHello(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Hello hello = (Hello) context.getBean("hello");
        hello.show();
    }

进行测试完之后,我们可以理解:

  • Hello对象是由Spring创建的
  • Hello对象的属性是有Spring容器设置的

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

控制:谁来控制对象的创建?传统应用程序的对象是由程序本身控制创建的;使用Spring后,对象则是由Spring来创建的。

反转:程序本身不创建对象,而变成被动地接受对象。

依赖注入:利用set方法来进行注入。

IOC是一种编程思想,由主动编程变为被动接受。

理解了IOC之后,我们可以彻底不用再去程序中进行改动了,要实现不同的操作,只需要在xml配置文件中进行修改。所谓的IOC,即 对象由Spring来创建,管理和装配。

IOC创建对象的方式

使用无参构造创建对象

可以使用无参构造创建对象,这是默认的方式。

使用有参构造创建对象

如果要使用有参构造来创建对象,有以下几种方式:

  • 下标赋值

    <!--第一种,下标赋值!-->
    <bean id="user" class="com.llx.pojo.User">
        <constructor-arg index="0" value="llx"/>
    </bean>
    
  • 类型

    <!--第二种方式:通过类型创建,不建议使用!-->
    <bean id="user" class="com.llx.pojo.User">
        <constructor-arg type="java.lang.String" value="LLX"/>
    </bean>
    
  • 参数名

    <!--第三种,直接通过参数名来设置-->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg name="name" value="LLX1"/>
    </bean>
    

在配置文件加载的时候,容器中管理的对象就已经初始化了!

Spring配置

别名

对对象设置别名,设置别名后,也可以通过别名获取到这个对象。

<alias name="user" alias="userNew"/>

Bean的配置

bean标签 中有几个常用的属性:

属性含义
idid是bean的唯一标识符,即相当于我们学的对象名
classclass是bean对象所对应的全限定名即 包名+类名
namename是别名,而且name可以同时取多个别名
<bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
        <property name="name" value="Spring"/>
</bean>

import

import,一般用于团队开发,可以将多个配置文件导入合并为一个。

将多个配置文件,使用import标签,导入在applicationContext.xml中即可。

<import resource="user.xml"/>
<import resource="hello.xml"/>
<import resource="bean.xml"/>

在使用的时候,使用总的配置文件applicationContext.xml即可。

依赖注入

依赖注入的方式有好几种:

  • 构造器注入
  • set方式注入
  • p命令空间和c命令空间

set方式注入

set注入:

  • 依赖:bean对象的创建依赖于容器
  • 注入:bean对象中的所有属性,由容器来注入

环境搭建

1、编写一个Address类,复杂类型:

package com.llx.pojo;

public class Address {
    private String address;

    private com.llx.pojo.Student student;

    public void setAddress(String address) {
        this.address = address;
    }

    public String getAddress() {
        return address;
    }
}

2、编写Student类,真实测试对象

package com.llx.pojo;

import java.util.*;

public class Student {

    private String name;
    private Address address;
    private String[] books;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;
    private String wife ;// null
    private Properties info;

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

    public void setAddress(Address address) {
        this.address = address;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.getAddress() +
                ", books=" + Arrays.toString(books) +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}

3、编写student.xml配置文件,并将其导入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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="student" class="com.llx.pojo.Student">
        <property name="name" value="llx"/>
    </bean>

</beans>

4、测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

完整的注入信息如下:

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="addr" class="com.llx.pojo.Address">
        <property name="address" value="西安"/>
    </bean>
    <bean id="student" class="com.llx.pojo.Student" scope="singleton">
        <!--第一种,普通值注入,value-->
        <property name="name" value="llx"/>
        <!--第二种,Bean注入,ref-->
        <property name="address" ref="addr"/>
        <!--数组-->
        <property name="books">
            <array>
                <value>西游记</value>
                <value>红楼梦</value>
                <value>水浒传</value>
            </array>
        </property>
        <!--List-->
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        <!--Map-->
        <property name="map">
            <map>
                <entry key="key1" value="v1"/>
                <entry key="key2" value="v2"/>
                <entry key="key3" value="v3"/>
            </map>
        </property>
         <!--Set-->
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>
        <!--null-->
        <property name="wife">
            <null/>
        </property>
        <!--Properties-->
        <property name="info">
            <props>
                <prop key="id">122</prop>
                <prop key="name">llx</prop>
                <prop key="sex">female</prop>
            </props>
        </property>
    </bean>
</beans>

拓展方式注入

可以使用 p命名空间和c命名空间进行注入。

<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--p命名空间注入,可以直接注入属性的值:property-->
    <bean id="user" class="com.llx.pojo.User" p:name="llx" p:age="20"/>

    <!--c命名空间注入,通过构造器注入:construct-args-->
    <bean id="user2" class="com.llx.pojo.User" c:age="20" c:name="llx2"/>

</beans>

测试:

@Test
public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = context.getBean("user2", User.class);
    System.out.println(user);
}

需要注意的是,p命名和c命名空间不能直接使用,需要导入xml约束才可以。

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

bean的作用域

单例模式

单例模式是Spring的默认机制。

<bean id="student" class="com.llx.pojo.Student" scope="singleton">
        <property name="name" value="刘丽侠"/>
</bean>

原型模式

原型模式,每次从容器中get的时候,都会产生一个新的对象

<bean id="student" class="com.llx.pojo.Student" scope="prototype">
        <property name="name" value="刘丽侠"/>
</bean>

其余的 request、session、application,这些只能在web开发中使用到。

Bean的自动装配

自动装配是Spring满足bean依赖的一种方式。

Spring会在上下文中自动寻找,并自动给bean装配属性。

在Spring中有三中配置的方式:

  • 在xml配置文件中显式地配置
  • 在java中显式地配置
  • 隐式地自动装配

自动装配有两种方式:ByName和ByType。

测试环境搭建:

以一个人有猫和狗两个宠物为例。

1、编写实体类:

Cat类

package com.llx.entity;

public class Cat {
    public void shout(){
        System.out.println("miao ~");
    }
}

Dog类

package com.llx.entity;

public class Dog {
    public void shout(){
        System.out.println("wang ~");
    }
}

User类

package com.llx.entity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.annotation.Resource;

public class User {
    private String name;
    private Cat cat;
    private Dog dog;

    public String getName() {
        return name;
    }

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

    public Cat getCat() {
        return cat;
    }
    
    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }
    
    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        dog.shout();
        cat.shout();
        return "User{" +
                "name='" + name + '\'' +
                ", cat=" + cat +
                ", dog=" + dog +
                '}';

    }
}

2、编写user.xml文件,并导入到applicationContext.xml中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="cat" class="com.llx.entity.Cat"/>
    <bean id="dog" class="com.llx.entity.Dog"/>

    <bean id="user" class="com.llx.entity.User">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
        <property name="name" value="llx"/>
    </bean>

</beans>

3、编写测试类

@Test
    public void test4(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        System.out.println(user.toString());

    }

ByName自动装配

设置bean的autowire属性为byName。

byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id。

 <bean id="cat" class="com.llx.entity.Cat"/>
 <bean id="dog" class="com.llx.entity.Dog"/>

 <bean id="user" class="com.llx.entity.User" autowire="byName">
     <property name="name" value="llx"/>
 </bean>

ByType自动匹配

设置bean的autowire属性为byType。

byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean

 <bean id="cat" class="com.llx.entity.Cat"/>
 <bean id="dog" class="com.llx.entity.Dog"/>

 <bean id="user" class="com.llx.entity.User" autowire="byType">
     <property name="name" value="llx"/>
 </bean>

总结:

  • 使用byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • 使用bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

使用注解实现自动装配

使用注解的时候,需要导入约束(context约束);配置注解的支持<context:annotation-config/>

在xml文件中配置<context:annotation-config/>

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

@Autowired注解

@Autowired注解可以直接在属性上使用,也可以在set方法是使用。

@Autowired 通过byType的方式实现。

使用@Autowired注解,我们可以不用编写set方法,但是前提是自动装配的属性在 IOC(Spring)容器中存在,且符合名字byname。

package com.llx.entity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.annotation.Resource;

public class User {
    private String name;
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;

    public String getName() {
        return name;
    }

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

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

    @Override
    public String toString() {
        dog.shout();
        cat.shout();
        return "User{" +
                "name='" + name + '\'' +
                ", cat=" + cat +
                ", dog=" + dog +
                '}';
    }
}

如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空。

如果 @Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解(@Autowired)完成的时候,我们可以使用@Qualifier(value=“xxx”)去配合@Autowired的使用,指定一个唯一的bean对象注入!

@Autowired
@Qualifier("dog1")  // 匹配指定对象,若没有,则会报红
private Dog dog;
<bean id="dog1" class="com.llx.entity.Dog"/>
<bean id="dog2" class="com.llx.entity.Dog"/>

@Resource注解

@Resource注解是java的注解,作用同 Autowired 和 Qualifier。

@ Resource 默认通过byname的方式实现。

@Resource(name = "cat2")   // java 的注解 配置 作用同 Autowired 和 Qualifier
private Cat cat;

@Resource 和@ Autowired 的区别:

  • 两者都是用来自动装配的,都可以放在属性字段上
  • @ Autowired 通过byType的方式实现,而且必须要求这个对象存在! 【常用】
  • @ Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错! 【常用】
  • 执行顺序不同:@ Autowired 通过byType的方式实现。@ Resource 默认通过byname的方式实现。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值