Spring5(2)-依赖注入

76 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

目录

一.基于配置文件的IOC

1.利用Spring容器中获取对象

2.利用配置文件注入-通过Spring给对象赋值

使用setter注入

使用构造方法注入

二.基于注解的IOC

1.利用注解获取对象 

2.利用注解注入

三.Spring配置文件的拆分和整合

四.其他


一.基于配置文件的IOC

1.利用Spring容器中获取对象

Step1:创建maven工程,在pom文件中添加Spring的核心jar包

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.commons/com.springsource.org.apache.commons.logging -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>com.springsource.org.apache.commons.logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.wagon</groupId>
            <artifactId>wagon-provider-api</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

Step2:创建Spring核心配置文件

​编辑

Step3:从Spring容器中获取对象

  • 创建实体类
  • xml文件中定义bean标签
  • 创建ApplicationContext容器,并取出对象
<bean id="stu" class="pojo.Student"></bean>
    <!--    等同于Student student = new Student();
        id是创建的对象的名称,唯一标识这个bean
        class是创建对象的类型
        启动容器的同时,这个对象就被创建了
-->
    

public static void getStudent(){
//2.从Spring容器中取出对象,得先创建容器对象,并启动才能取对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = (Student) ac.getBean("stu");

    }

2.利用配置文件注入-通过Spring给对象赋值

使用setter注入

要求

使用setter注入时,实体类中必须有无参构造set方法。

因为使用setter注入时,要先创建出对象,再给对象赋值,所以要有无参构造。

简单类型注入

通过property,name,value

public class Student {
    private String name;
    private int age;
  
    public Student() {
        System.out.println("学生无参构造");
    }

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

    public void setAge(int age) {
        this.age = age;
    }
}

<bean id="stu" class="pojo.Student">
    <property name="name" value="张三"></property>
    <property name="age" value="18"></property>
</bean>

引用类型注入

通过property name ref

public class Student {
    private String name;
    private int age;
    private School school;

    public Student() {
        System.out.println("学生无参构造");
    }

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

    public void setAge(int age) {
        this.age = age;
    }

    public void setSchool(School school) {
        this.school = school;
    }
}

    <bean id="school" class="pojo.School">
        <property name="name" value="青岛大学"></property>
        <property name="address" value="青岛"></property>
    </bean>

    <bean id="stu" class="pojo.Student">
        <property name="name" value="张三"></property>
        <property name="age" value="18"></property>
        <property name="school" ref="school"></property>
    </bean>

引用类型的自动注入

    <bean name="student" class="pojo.Student" autowire="byType">
        <property name="name" value="张三"></property>
        <property name="age" value="18"></property>
    <!--    <property name="school" ref=""></property>-->
    </bean>
    <bean name="school" class="pojo.School">
        <property name="name" value="青大"></property>
        <property name="address" value="青岛"></property>
    </bean>

通过autowire自动注入引用类型,不需要写property标签了

使用构造方法注入

通过构造方法注入时,是在创建对象的过程中就赋值了,所以要有对应参数个数的构造方法,不能仅有无参构造。

使用构造方法的参数名称进行注入值

构造方法标签中的name属性值是构造方法形参的名字

public class School {
    private String name;
    private String address;

    public School(String name1, String address1) {
        this.name = name1;
        this.address = address1;
    }
}

<bean id="school" class="pojo.School">
    <constructor-arg name="name1" value="青岛大学"></constructor-arg>
    <constructor-arg name="address1" value="青岛"></constructor-arg>
</bean>

使用构造方法参数的下标注入值

<bean id="school" class="pojo.School">
    <constructor-arg index="0" value="青岛大学"></constructor-arg>
    <constructor-arg index="1" value="青岛"></constructor-arg>
</bean>

构造器中的参数的顺序序号

使用默认的构造方法的参数的顺序注入值

<bean id="school" class="pojo.School">
    <constructor-arg  value="青岛大学"></constructor-arg>
    <constructor-arg  value="青岛"></constructor-arg>
</bean>

这个顺序是和构造器中参数的顺序一致

二.基于注解的IOC

要求

1.基于注解的IOC需要在Spring配置文件中添加包扫描,并且需要无参构造。

<context:component-scan base-package="pojo"></context:component-scan>

扫描包的方式

​编辑

扫描根包会导致容器扫描很多无用的路径,使启动速度降低。

2.每个类要加上@Component注解

1.利用注解获取对象 

​编辑

扫描某个包,只要扫到包中哪个类有这几个注解,就马上创建这个类的对象。

@Component
public class Student {
    private String name;
    private int age;
    private School school;
}

public class Test {
    @org.junit.Test
    public void test(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student school = (Student) ac.getBean("student");
        System.out.println(school);
    }
}

用注解时获取对象时,默认对象的名字是类名的小写。如Student类的对象名是student

也可以给对象指定名字

@Component("stu")
public class Student {
    private String name;
    private int age;
    private School school;
}

2.利用注解注入

​编辑

同源类型:

​编辑

值类型注入

@Component("stu")
public class Student {
    @Value("张三")
    private String name;
    @Value("18")
    private int age;
}

引用类型按类型注入

扫描整个被Component注解的类,看哪个是School类型,School类型需要加上@Component注解才能被扫描到,被扫描到后就可以给引用类型赋值,因为类名不允许重,所以可以保证唯一。

@Component
public class School {
    @Value("青岛大学")
    private String name;
    @Value("青岛")
    private String address;
}

@Component
public class Student {
    @Value("张三")
    private String name;
    @Value("18")
    private int age;
    @Autowired
    private School school;
}

引用类型按名称注入

按名称注入时,只要@Qualifier不能承担起这个功能,必须还要有@Autowired这个注解

@Component("sch")
public class School {
    @Value("青岛大学")
    private String name;
    @Value("青岛")
    private String address;
}

@Component
public class Student {
    @Value("张三")
    private String name;
    @Value("18")
    private int age;
    @Autowired
    @Qualifier("sch")
    private School school;
}

有父子类的情况

使用按类型注入时,意味着有多个可注入的对象,假如要注入School类型,而SubSchool继承School,那么School类和SubSchool类都属于School类,注入时选择哪个类的对象呢?

这时会按照名称进行二次筛选,比如要注入School类型,就去筛选school名称的对象,School类的默认名称是school,SubSchool类的默认名称是subSchool,名称是可以通过@Component("")来修改的

按名称注入值时, 跟上面无父子类的情况一样。

三.Spring配置文件的拆分和整合

当项目越来越大,需要多人合作开发,一个配置就存在很大的隐患,所以需要拆分。

拆完编辑好之后就需要组合到一起才能实现功能。

​编辑

按层拆分的例子

​编辑

基于注解时每个applicationContext都是扫描包,不使用注解时,每个配置文件写的是bean。

单个导入

<?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">

<!--    单个导入-->
    <import resource="applicationContext_controller.xml"></import>
    <import resource="applicationContext_service.xml"></import>
    <import resource="applicationContext_mapper.xml"></import>
</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">

<!--    批量导入-->
    <import resource="applicationContext_*.xml"></import>

</beans>

四.其他

三层架构

​编辑

model层也叫pojo层或entity层

dao层也叫mapper层

service层

controller层

创建对象

单态模式

<bean id="user" class="pojo.User" scope="singleton"></bean>

原型模式

<bean id="user" class="pojo.User" scope="prototype"></bean>

单态模式中调用getBean如果id相同,返回的对象是同一个,原型模式中调用几次getBean就会产生几个对象

在代码中获取对象

public static void getUser(){
        //加载spring.xml配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        User user = (User) ac.getBean("user2");
    }

注入(给对象属性赋值)

1.简单数据类型

public class User {
    private String username;
    private int age;
}

<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        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
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
">
    
    <bean id="user" class="pojo.User" scope="singleton">
        <property name="username" value="cc"></property>
        <property name="age" value="18"></property>
    </bean>


</beans>

2.引用数据类型注入

public class User {
    private String username;
    private int age;
    private Account account;
}

    <bean id="user" class="pojo.User" scope="singleton">
        <property name="username" value="cc"></property>
        <property name="age" value="18"></property>
        <property name="account" ref="account"></property>
    </bean>
    

    <bean id="account" class="pojo.Account">
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="money" value="100"></constructor-arg>
    </bean>

3.构造器注入

public class User {
    private String username;
    private int age;

    public User() {
    }

    public User(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

    <bean id="user2" class="pojo.User">
        <constructor-arg name="username" value="zz"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
    </bean>

局部和全自动注入

局部自动注入,只在某个bean中有效

<bean id="user" class="pojo.User" scope="singleton" autowire="byName">
        <property name="username" value="cc"></property>
        <property name="age" value="18"></property>
<!--        <property name="account" ref="account"></property>-->
<!--        user有个名为account的属性,如果没有给这个属性赋值,会自动去寻找在bean中名为account的属性自动注入-->
    </bean>
    

    <bean id="account" class="pojo.Account">
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="money" value="100"></constructor-arg>
    </bean>

    <bean id="user" class="pojo.User" scope="singleton" autowire="byType">
        <property name="username" value="cc"></property>
        <property name="age" value="18"></property>
<!--        <property name="account" ref="account"></property>-->
<!--        通过类型注入,名字不一样,但是都属于Account类,也可以根据这个来判断注入-->
    </bean>
    

    <bean id="acc" class="pojo.Account">
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="money" value="100"></constructor-arg>
    </bean>

全局自动注入

写到这上面的话,就可以全局自动注入,每个bean都默认根据类型注入

<?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" default-autowire="byType">

</beans>

空字符串注入

方式1

<bean id="user" class="pojo.User" scope="singleton" autowire="byType">
        <property name="username" value=""></property>
        <property name="age" value="18"></property>
    </bean>

方式2

    <bean id="user" class="pojo.User" scope="singleton" autowire="byType">

        <property name="username"><value/></property>
        <property name="age" value="18"></property>
    </bean>

null值注入

     <bean id="user" class="pojo.User" scope="singleton" autowire="byType">
        <property name="username"><null/></property>
        <property name="age" value="18"></property>
    </bean>

什么也不写也是注入null

     <bean id="user" class="pojo.User" scope="singleton" autowire="byType">
        <property name="age" value="18"></property>
    </bean>

数组注入集合properties注入

<bean id="data" class="pojo.Data">
        <property name="arr">
            <array>
                <value>A</value>
                <value>B</value>
                <value>C</value>
                <value>D</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="set">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="m" value="3"></entry>
                <entry key="n" value="3"></entry>
                <entry key="q" value="3"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="zxc">123</prop>
                <prop key="asd">456</prop>
            </props>
        </property>
    </bean>

public class Data {
    private String[] arr;
    private List list;

    private Set set;

    private Map<String,Integer> map;

    private Properties properties;


    public String[] getArr() {
        return arr;
    }

    public void setArr(String[] arr) {
        this.arr = arr;
    }

    public List getList() {
        return list;
    }

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

    public Set getSet() {
        return set;
    }

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

    public Map<String, Integer> getMap() {
        return map;
    }

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

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

基于注解注入

​编辑

public class Test {
    public static void main(String[] args) {
        Test.getUser();
    }
    public static void getUser(){
        //加载spring.xml配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        User user = (User) ac.getBean("user");
        System.out.println(user);
    }
}

@Component //表示在扫描pojo这个包下所有的类时,告诉spring容器当前User这个类交给Spring容器管理
//默认将类名的小写作为id名
public class User {
    @Value("zz")
    private String username;
    private int age;
    
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    @Value("18")
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + ''' +
                ", age=" + age+'}' ;
    }
}

<?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:component-scan base-package="pojo"></context:component-scan>

</beans>

也可以更改默认id名

@Component("uu")

public class Test {
    public static void main(String[] args) {
        Test.getUser();
    }
    public static void getUser(){
        //加载spring.xml配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        User user = (User) ac.getBean("uu");
        System.out.println(user);
    }
}

@Scope注解

@Component()
//@Scope("singleton")
@Scope("prototype")
public class User {
    @Value("zz")
    private String username;
    private int age;
}

@Autowired注解

根据类型自动匹配

@Component() 
public class User {
    @Value("zz")
    private String username;
    private int age;
    @Autowired
    private Account account;

@Component
public class Account {
    @Value("10")
    private int id;
    @Value("100")
    private double money;
}

@Resouce注解

@Required表示必须赋值,如果不赋值就会报错

如果在set方法上加了Required声明,那么必须把@Value放在set方法上,不能放在属性上

\