Spring基础-依赖注入控制翻转

1、spring注入

spring的注入,就是对bean对象的属性设置值

2、为什么需要注入

这里我们可以先看一段代码

    @Test
    public void testInject(){
        ClassPathXmlApplicationContext cxt = new ClassPathXmlApplicationContext("/applicationContext.xml");
        Person person = cxt.getBean("person", Person.class);

        person.setAge(18);
        person.setName("zhangsan");

        System.out.println(person);

    }

小伙伴们可以发现,我们通过getBean()取出来的对象,想要给这个对象赋值,是使用的setXX()方法,这也是一种耦合。那么可不可以让spring在初始化的时候就将bean对象给我们设置好,getBean()放回的时候,直接给我们一个完整的对象呢??

答案肯定是可以的,这里就需要引入spring的注入

3、spring的注入

spring的注入其实也非常简单,我们只需要在applicationContext.xml文件中进行配置下即可

    <bean id="person" name="p1" class="com.wx.study.Person">
        <property name="name">
            <value>zhangsan</value>
        </property>
        <property name="age">
            <value>18</value>
        </property>
    </bean>

通过截图发现,spring确实帮我们将属性设置进去了。我们这么做的好处,就是解耦

注意点:

  • 我们的实体类中一定要添加setXX()方法,不然spring是没有办法帮助我们注入属性

3.1注入的原理

原来我们的setXX()方法约等于我们配置中的<property>配置,spring的底层是调用我们实体类的setXX()方法,所以我们想要spring帮助我们set注入,就一定需要生成set方法。用配置来实现注入的好处是解耦。

4、spring的注入方式

4.1、set注入

set注入分为注入两种:

  1. jdk内置对象
  2. 用户自定义对象

4.1.1、jdk内置对象

java中八种基础对象加上String类型的字符串,在配置文件中都是使用<property><values>XXX</values></property>来表示

    private String name;

    private int id;
    private boolean isBoolean;
    private float score;
    private char sex;
    private double money;
    private long aLong;
    private byte aByte;
    private short aShort;
        <property name="name">
            <value>xiaoming</value>
        </property>
        <property name="id" value="20"></property>
        <property name="aByte" value="1"></property>
        <property name="aLong" value="10000"></property>
        <property name="boolean" value="false"></property>
        <property name="money" value="20.8"></property>
        <property name="score" value="100.12"></property>
        <property name="sex" value="1"></property>
        <property name="aShort" value="1"></property>

 java中集合对象的注入方式

根据不同的集合类型,我们注入的配置也是不一样的。

    private int[] ints;

    private List<String> address;

    private Set<String> sets;
    private Map<String, String> maps;
        <property name="ints">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="address">
            <list>
                <value>123</value>
                <value>456</value>
                <value>789</value>
            </list>
        </property>
        <property name="sets">
            <set>
                <value>123</value>
                <value>456</value>
                <value>789</value>
            </set>
        </property>
        <property name="maps">
            <map>
                <entry >
                    <key><value>1</value></key>
                    <value>111</value>
                </entry>
                <entry>
                    <key><value>2</value></key>
                    <value>222</value>
                </entry>
                <entry>
                    <key><value>3</value></key>
                    <value>333</value>
                </entry>
            </map>
        </property>

4.1.2、用户自定义对象

 使用用户自定义对象,我们需要使用<ref bean=""></ref>标签

    private Person person;
        <property name="person" >
            <ref bean="person"></ref>
        </property>

 

4.2、构造器注入

    public Students(String name, int id) {
        this.name = name;
        this.id = id;
    }
        <constructor-arg type="java.lang.String">
            <value>zhangsan</value>
        </constructor-arg>
        <constructor-arg type="int">
            <value>18</value>
        </constructor-arg>

我们将配置文件中的property标签注释,使用构造器注入。构造器注入使用的是<constructor-arg>标签,最好使用在标签中加入type用于区分类型。 

我们大部分使用的还是set注入的方式。 因为构造器注入有点麻烦

5、控制翻转

控制翻转,就是讲我们的对象交给spring来进行管理,之前我们需要使用一个对象,就是直接new出来,现在有了spring,对象都交由spring来帮助我们创建,我们需要的时候,直接找spring获取即可。

这么做的好处就是解耦合。而spring实现的方式是工厂模式。

这个代码就是典型的耦合,使我们自己new出来的对象。后期,如果实现类发生了改变,或者需要使用其他的实现类,我们都需要去修改代码。这就是一个典型的耦合案例!

public class PersonServiceImpl implements PersonService {
    
    private PersonDao personDao = new PersonDao();
    
    @Override
    public void save() {
        personDao.save();
    }
}

有了spring后,我们将写一个配置文件,将bean对象交给spring来进行管理,需要的时候我们只需要找spring获取即可。后期,如果需要替换其他实现类,也只需要修改一下配置文件即可

public class PersonDao {
    public void save() {
        System.out.println("保存");
    }
}
public class PersonServiceImpl implements PersonService {

    private PersonDao personDao;
    // private PersonDao personDao = new PersonDao();

    @Override
    public void save() {
        personDao.save();
    }

    public PersonDao getPersonDao() {
        return personDao;
    }

    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }
}
    <bean name="personDao" class="com.wx.dao.PersonDao"></bean>

    <bean name="personService" class="com.wx.service.impl.PersonServiceImpl">
        <property name="personDao" ref="personDao"></property>
    </bean>

我们可以看到,现在已经一步一步的开始解耦了。

控制翻转其实就是:spring配置文件 + Spring工厂(ApplicationContext)

6、spring工厂创建复杂对象

6.1、什么是简单对象

我们直接用new出来就可以使用的对象,就是简单对象。反射的底层,也是使用的构造方法

6.2、复杂对象

不能通过直接new来创建的,比如Connection对象,这种对象创建过程复杂

6.3、创建复杂对象的三种方式

创建复杂对象有三种方式:

  • 实现FactoryBean接口
  • 实例工厂
  • 静态实例工程

6.3.1、实现FactoryBean接口

实现FactoryBean接口,需要实现它的三个方法:

  • getObject():用于书写复杂对象创建的代码,将创建的复杂对象返回出去
  • getObjectType():返回复杂对象对应的.class文件
  • isSingleton():如果这个复杂对象只用创建一次,返回true;如果这个复杂对象每次都需要创建一个新的对象,返回flase
public class PersonBean implements FactoryBean<Person> {
    @Override
    public Person getObject() throws Exception {
        Person person = new Person();
        person.setName("zhaoliu");
        person.setAge(20);

        return person;
    }

    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }

    /**
     * 如果这个对象只需要创建一次,返回true
     * 如果每次调用都需要创建一次,返回false
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}
    <bean name="personBean" class="com.wx.study.PersonBean">

    </bean>

 

我们可以发现一个问题,为什么我们getBean()是personBean对象,但是给我们真是返回的是Person对象呢?

这是因为我们personBean对象是一个复杂对象,spring首先会判断我们的对象是否继承了FactoryBean接口,没有继承,直接new一个对象给我们返回。如果继承了,会调用我们的getObject()方法,返回给我们一个复杂对象。这也是为啥我们最后返回的是person对象的原因。

我们的isSingleton()方法如何返回的是true,我们每次调用getBean()方法的时候,复杂对象只会创建一次,后面调用就直接返回接口。然后这里是flase,那么每次调用getBean()方法,都会给我们重新创建一个实例。

6.3.2、实例工厂

为啥我们有了FactoryBean接口了,还需要实例工厂呢?这是因为为了方便继承一些已经存在的代码,将他们也交由spring来进行管理

遗留代码:

/**
 * 遗留代码
 */
public class OldFactory {

    public Person getOldPerson(){
        System.out.println("我是遗留代码");
        return new Person();
    }
}
<bean name="oldFactory" class="com.wx.study.OldFactory"></bean>
<bean name="personOld" factory-bean="oldFactory" factory-method="getOldPerson"></bean>

需要现将OldFactory类交给spring来进行管理,然后通过factory-bean(调用哪个bean对象)factory-method(调用哪个方法来创建对象)来进行操作

 

6.3.3、静态实例工厂

静态工厂就是调用的方法是静态的

/**
 * 静态工厂
 */
public class StaticOldFactory {

    public static Person getOldPerson(){
        System.out.println("我是静态遗留代码");
        return new Person();
    }
}

 因为是调用静态方法,所以我们的配置文件可以这样改写

<bean name="oldFactory" class="com.wx.study.OldFactory" factory-method="getOldPerson"></bean>

7、总结依赖注入和控制翻转

依赖注入有两种:

  • set注入
    • 八种基本数据类型
    • String类型
    • 集合类型
    • 用户自定义类
  • 构造器注入

控制翻转是将new的对象交由spring来进行创建管理,我们需要直接找spring获取

控制翻转分为以下两种:

  • 简单对象
  • 复杂对象
    • FactoryBean
    • 实例工厂
    • 静态工厂
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值