Spring——DI和通过注解实现IOC和DI

DI(依赖注入)

- 问题的提出:
之前所说的IOC,其中没有提到,如果当spring保存的类中有其他属性需要赋值的话怎么办(其实可以用工厂模式来完成),所以今天我们就来解决这个问题。
- DI的概念:
当spring容器创建对象的时候,通过xml配置文件,把需要赋值的JavaBean属性设置在配置文件中,这样就可以把值赋到了对应的属性上。
- 成员属性和JavaBean属性:
JavaBean属性=成员属性吗?答案是否定的,成员属性是在类里的,而JavaBean属性则是由类中的成员属性是否有set方法决定的,这里后面通过代码再进行解释。
- 注入方法1——set注入
注入普通属性:
配置文件中,通过name属性关联上类中的setXXX()方法,value中填入需要保存的值,配置文件代码如下。

<bean id="user" class="cn.tdu.bean.user">
    <property name="name" value="lxh"></property>
    <property name="age" value="23"></property>
    <property name="list">
        <list>
            <value>a1</value>
            <value>a2</value>
        </list>
    </property>
    <property name="set">
        <set>
            <value>b1</value>
            <value>b2</value>
        </set>
    </property>
    <property name="map">
        <map>
            <entry key="1" value="c1"></entry>
            <entry key="2" value="c2"></entry>
        </map>
    </property>
</bean>

从上述代码可以看到如何通过配置文件,注入属性给对应的属性,这里做几点说明, 标签中的name属性,对应的是类中的setXXX()方法中的xxx,该属性也可以称为JavaBean属性,如类中有setAge()方法,则name=“age”,绑定到的就是该方法。

注入自定义属性:
当需要注入的属性中,包含对象这种自定义的属性,则注入方式和上述普通属性就有所区别,代码如下。
在这里插入图片描述
和普通属性注入的区别是,不使用value属性,取而代之的是ref属性,该属性里写的是另一个bean的id,其中这个新声明的bean则是自定义属性。
自定义属性注入的自动装配:
自动装配的两种方法:
byName和byType,前者是根据javabean中需要注入的属性的名字 ,在spring容器中找对应id的将该的对象复制给 当前的属性,后者根据javabean中需要注入的属性的类型,在spring容器中找对应class类型的将该的对象复制给当前的属性。
关键字为:autowrite=” ? “
自动装配的两种范围:
指定bean进行关键字声明,只有该bean自动装配
把关键字写再beans下,全部bean都实行自动装配
代码如下:

//指定bean自动装配
<bean id="teacher" class="cn.tedu.beans.Teacher" autowire="byName</bean>
        <bean id="dog" class="cn.tedu.beans.Dog"></bean>
//全局默认自动装配
<beans ........default-autowire="byName" >
  • 注入方法2——基于构造方法的注入
    上述方法1,是基于有无参构造方法,当程序里have有参构造的时候,就可以使用该方法,该方法很简单,只用修改xml配置文件即可,代码如下。
<bean id="student" class="cn.tedu.beans.Student">
                <constructor-arg index="0" name="id" value="1"/>
                <constructor-arg index="1"type="java.lang.String"value="lxh"/>
                <constructor-arg name="dog" ref="dog"/>
        </bean>        
        <bean id="dog" class="cn.tedu.beans.Dog"></bean>

constructor-arg是标签关键字,在bean中写上这个标签,则说明使用基于构造方法的注入,当spring开始解读xml文件读到这句话的时候,就自动使用构造方法注入。
参数解释:
index:为构造方法的第几个参数 进行配置
name:为构造方法的哪个名字的参数进行配置
type:该构造方法参数的类型
value:该构造方法参数的值 ,用来指定基本值
ref:该构造方法参数的值,用来指定引用其他bean的值
注意:index 和 name 可以配置任何一个或同时配置 但要求一旦配置必须正确,推荐优先使用index方式配置 防止没有源码造成name无法匹配到对应参数

通过使用注解实现IOC

引入:
之前我们已经说过,IOC就是把创建对象和销毁对象的工作交给spring来完成,这之中有很大的工作量都是在配置xml文件上,如果项目足够大,可能xml里会有成千上万个bean,修改起来真的很浪费时间,所以由此就产生了新的技术——注解。

注解实现IOC:
实现逻辑
上图解释了注解是如何被识别出来,以及如何创建对象保存在spring内置map中。在需要交给spring来管理的类上添加一个@Component(“dog”),其中dog是我自定义的id,用来存入map中。通过上面注解的方式,在xml文件中就只用书写一个包扫描就可以。

注解实现工厂模式:
工厂模式其实和实现IOC大同小异
第一步:在工厂类外部添加@Component注解,表示该工厂类需要交给spring来管理。
第二步:工厂类中,创建对象的方法上放,添加@Bean(“自己设置d”)。当spring通过@Component,找到该类,并且发现里面有@Bean注解的方法,则会调用该方法返回对象,对象id可以自己设置,将返回的对象和id存入map中。

通过注解实现DI

注入普通属性,不包括集合:
在这里插入图片描述
代码如下:

配置文件中的代码:
<!--开启包扫描-->
      <context:component-scan base-package="cn.tdu.bean"></context:component-scan>
<!--开启属性注入-->
      <context:annotation-config></context:annotation-config>
<!--声明properties-->
      <context:property-placeholder location="user.properties"/>
类中的代码:
public class user {
    @Value("${name}")
    private String name;
    private List<String> list;
    private Set<String> set;
    private Map<String,String> map;
    private dog dog;
    ..........

这一块我只注入了name属性,因为集合和自定义属性需要其他方式来注入,善于观察的小伙伴应该已经发现,我这里的value里,写法似乎有些奇怪,这是因为我把属性的值放入了properties文件中,直接从文件中获取,这样以后修改代码的时候,就只用修改properties,而不用修改代码。

注入集合:
集合的注入和注入普通属性有些区别但是过程和上面流程图一样。首先在xml配置文件中通过util名称空间来初始化集合数据,接着通过@value("#{@s1}")来类中绑定变量,其中s1是自定义的名字。代码如下:

//xml配置文件中
<!--配置集合数据-->
      <util:list id="l1">
            <value>a1</value>
            <value>a2</value>
      </util:list>
      <util:map id="m1">
            <entry key="1" value="b1"></entry>
            <entry key="2" value="b2"></entry>
      </util:map>
//类中
public class user {
    @Value("${name}")
    private String name;
    @Value("#{@l1}")
    private List<String> list;
    private Set<String> set;
    @Value("#{@m1}")
    private Map<String,String> map;
    private dog dog;
    .........

注入自定义属性
在类中自定义属性上添加@Autowired和@Qulifier,则spring在读取到该注解时,则知道这是一个自定义属性类型,然后开始在spring容器中开始寻找该自定义属性,寻找方式如下:

  • 同时配置了@Autowired和@Qulifier:
    则直接按照指定id(如果不指定则用变量名作为id)寻找bean,找到就注入,找不到抛出异常

  • 如果只配置了@Autowired:
    则先按照类型匹配,如果找到唯一的,注入
    如果找不到或找到多个,则开始按照id注入
    按照id寻找,如果找到唯一的注入,找不到就抛出异常

代码如下:

public class user {
    @Value("${name}")
    private String name;
    @Value("#{@l1}")
    private List<String> list;
    private Set<String> set;
    @Value("#{@m1}")
    private Map<String,String> map;
    @Autowired
    @Qualifier("dog")//直接按照ID为dog,开始寻找spring中的bean。如果不写@Qualifer,则按照dog类型去寻找
    private dog dog;
    .......
 //dog类
 @Component("dog")
    public class dog {
     @Value("cc")
     private String name;
    .......

其他注解

1.@Scope(value=“prototype”)
用来确定该bean是单例还是多例

@Component
@Scope("prototype")
public class Teacher {
}

2.@Lazy
确实该bean是否是懒加载机制

@Component
@Lazy
public class Teacher {
}

3.@PostConstruct和 @PreDestroy
修饰bean中的方法,分别是初始化方法和销毁方法,创建对象时自动调用

@Component
public class Dog {
       @PostConstruct
       public void init(){
                System.out.println("Dog的初始化方法。。。");
        }
       
        @PreDestroy
        public void destory(){
                System.out.println("Dog的销毁方法。。。");
        }
}

4.@Controller @Service @Repository @Component
这四个功能完全相同,都是用来修饰类的,修饰过的就成为了bean,被spring管理。

其中@Component一般认为是通用的注解

而@Controller用在软件分层中的控制层,一般用在web层

而@Service用在软件分层中的业务访问层,一般用在service层

而@Repository用在软件分层中的数据访问层,一般用在dao层

猜你喜欢

转载自blog.csdn.net/weixin_42596778/article/details/105821588