Spring DI

Spring IOC

对Spring ioc的介绍及使用,与下文相连:
Spring ioc

DI 依赖注入

DI(Dependency Injection)依赖注入,指容器复制创建和维护对象之间的依赖关系,而不是通过对象本身复制自己的创建和解决自己的依赖。控制反转是通过依赖注入实现的。

其实Ioc和DI在Spring中是一个等同的概念。如果非要咬文嚼字的话,控制反转是依赖注入的一部分,或者说是同一个行为偏重点不同的俩个称呼。

他们是从不能的角度阐述同一个功能,描述的对象不同而已。依赖注入是从程序本身来说,控制反转是从容器来说的。

DI 关键点

关键点:“谁依赖谁?为什么需要依赖?谁注入谁?注入了什么?”
容器:IOC
组件:(某一个特定的类:例如:UserService)
资源:(组件依赖的内容:例如:mailService)

谁依赖于谁:应用程序依赖于IOC容器
为什么需要依赖:应用程序需要IOC容器提供组件需要的外部资源
谁注入谁:IOC容器注入应用程序需要的资源,组件依赖的资源
注入了什么:注入了某个对象所需要的外部资源(包括对象,常量数据,资源)

依赖注入方式

基于xml配置文件注入

基于有参构造函数注入

给定对象Person,并给定其有参构造函数

public class Person {
    private String name;
    private int id;
    
    public Person(String name,int id){
        this.id = id;
        this.name = name;
    }
    //省略set和get方法
    }

在appLication.xml配置文件中配置相应属性

  <!--基于有参构造函数注入依赖-->
    <bean id="person4" class="com.tulun.bean.Person">
        <constructor-arg name="id" value="1"/>
        <constructor-arg name="name" value="wu"/>
    </bean>

通过< constructor-arg >标签注入属性
测试(App,java)

    //基于有参构造函数注入依赖
    public void demo5(){
        //获取IOC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        //在容器中获取需要的对象
        Person person = (Person) context.getBean("person4");
        System.out.println(person);
    }

基于set()方法注入

对应的对象类提供set()方法

public class Person {
    private String name;
    private int id;

    public Person(){}
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", person1=" + person1 +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

在application.xml文件中使用property标签配置属性

    <!--基于set方法注入依赖-->
    <bean id="person5" class="com.tulun.bean.Person">
    <property name="name" value="li"/>
        <property name="id" value="2"/>
        </bean>
当存在自定义类型属性时,set()方法

对象类中存在自定义类型的属性

public class Person {
    private String name;
    private int id;
    //自定义属性
    private Person1 person1;
    public void setPerson1(Person1 person1) {
        this.person1 = person1;
    }
    //省略set和get方法
    }

application.xml配置文件中的配置

    <bean id="person" class="com.tulun.bean.Person1"/>
    <!--基于set方法注入依赖-->
    <bean id="person5" class="com.tulun.bean.Person">
    <property name="name" value="li"/>
        <property name="id" value="2"/>
        <!--自定义属性-->
        <property name="person1" ref="person"/>
    </bean>

通过set方法注入依赖使用< property >标签,name属性对应的是类中属性名 value对应是赋予的值(只针对基本类型,作为String)
自定类型的注入使用的是ref标签

其他类型的数据注入

注入数据处理基本类型,自定义类型,Spring中还支持List、map、set、array等类型的数据注入
例如:
在对象类中添加对应类型属性

    private List<String> ls;
    private Map<String,String> ms;

    public void setLs(List<String> ls) {
        this.ls = ls;
    }
    public void setMs(Map<String, String> ms) {
        this.ms = ms;
    }

相应配置文件

        <!--注入list类型-->
        <property name="ls">
            <list>
                <value>12</value>
                <value>13</value>
            </list>
        </property>
        <!--注入map类型数据-->
        <property name="ms">
            <map>
                <entry key="" value=""/>
                <entry key=" " value=""/>
            </map>
        </property>

基于注解注入

xml配置文件(application1.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!--开启注解扫描:在指定的包路径下所有的类名,属性等上的注解都会进行扫描-->
    <context:component-scan base-package="com.tulun"/>

</beans>

在对应的依赖上添加注解@Autowired

@Service(value = "userService")
//service注解是装配bean
public class UserService1 {
    @Autowired
    //Aotowired是用来注入依赖的
    private MailService mailService;
}

@Value注入普通的类型属性
@Resource 注入的是对象类型
@Autowired 注入对象类型

实现Demo

@Component(value = "user")
public class User12 {
    @Value("2")
    private Integer id;
    @Value("zhangsan")
    private String name;
    private String passwd;
    private String address;

    public User12() {}

//    有参构造函数
    public User12(Integer id, String name, String passwd, String address) {
        this.id = id;
        this.name = name;
        this.passwd = passwd;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getAddress() {
        return address;
    }

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

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("{");
        sb.append("\"id\":")
                .append(id);
        sb.append(",\"name\":\"")
                .append(name).append('\"');
        sb.append(",\"passwd\":\"")
                .append(passwd).append('\"');
        sb.append(",\"address\":\"")
                .append(address).append('\"');
        sb.append(",\"person\":")
                .append(person);
        sb.append('}');
        return sb.toString();
    }
    
}

@Service(value = "mailService")
public class MailService {

    public void sendLoginMail(User12 user) {
        System.err.println(String.format("Hi, %s! ", user.getName()));
    }

    public void sendRegistrationMail(User12 user) {
        System.err.println(String.format("Welcome, %s!", user.getName()));

    }
}
@Service(value = "userService")
public class UserService1 {
    @Autowired
    private MailService mailService;


    private List<User12> users = new ArrayList<User12>();


    public User12 login(String name, String password) {
        for (User12 user : users) {
            if (user.getName().equalsIgnoreCase(name) && user.getPasswd().equals(password)) {
                mailService.sendLoginMail(user);
                return user;
            }
        }
        throw new RuntimeException("login failed.");
    }

    public User12 getUser(long id) {
        for (User12 user : users) {
            if (user.getId() == id) {
                return user;
            }
        }
        return null;
    }

    public User12 register(String name, String password, String address) {
        User12 user = new User12(users.size()+1, name, password, address);
        users.add(user);
        mailService.sendLoginMail(user);
        mailService.sendRegistrationMail(user);
        return user;
    }
}

@Resource和@Autowired的区别?

@Resource和@Autowired都是用来做bean的注入时使用的,@Resource和@Autowired在有时是可以互相替换换使用的,但是有的时候是不可以的?

功能点:
@Resource和@Autowired都作为bean的注入使用的,在接口仅有一个实现类时,两个注解的修饰效果相同,可以相互替换

不同点:
@Resource是Java自己的注解,
@Resource注解有两个属性比较重要,一个是name,一个是type
spring中使用时name属性解析为按照bean中名称,使用type时解析为类型,如果没有给定属性值,spring的反射机制通过byName来自动注入属性
@Autowired是spring提供的注解,在spring2.5版本后引入的只根据type去进行注入,不用name ,如果涉及到type无法识别注入对象时,仅使用@Autowired是无法完成注入的,需要借助其他的注解一块才能完成

依赖的解析过程

在spring的依赖的解析过程:
1、ApplicationContext通过配置的元数据来创建和初始化,这些元数据描述了所有的bean,
元数据的信息是可以通过注解,xml或者是Java代码来描述
2、对于每一个bean,他的依赖用属性、构造函数或者是静态工厂方法等形式来表达,bean被创建好之后这些依赖会提供给他
3、每一个属性或者构造方法都要被设置的值的实际定义,或者是对容器中的另一个bean的引用
4、每个属性或者构造方法的值的实际定义都会转化为当前实例bean的实际的值
在容器创建的过程中,spring容器会验证每一个bean的配置,在实际创建bean之前,bean的属性不会被设置,单例和被设置为首先加载的bean会在容器初始化后就创建出来,
其他的bean只会在需要的时候才会创建,创建bean过程可能会引起一系列的bean被创建,

循环依赖:
A->B
B->A
A ->B->C->F
D->E->C->B
高频的问题:循环依赖的问题
解决途径是:这些类可以通过setter注入,避免使用构造方法注入

创建顺序:
A B
构造函数构造A ,依赖B 创建顺序:B-A
Set方法创建A, 注入B 创建顺序:A-B

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值