基于注解的DI

通过spring的注解完成对java对象的创建,属性的赋值,代替xml文件

ioc能够实现业务和对象之间的解耦合,例如service和dao对象之间的解耦合

常用注解:

  • @Component、创建对象
  • @Respotory、创建dao对象,用来访问数据库
  • @Service、创建Service对象,处理业务逻辑,可以有事务的功能
  • @Controller、创建控制器对象,接收请求,显示处理结果
  • @Value、简单类型的属性赋值
  • @Autowired、spring框架中引用类型赋值的注解,支持byName、byType,默认byType
  • @Resource、jdk中的注解,使用自动注入给引用数据类型赋值,支持byName、byType,默认byName

一、使用注解的步骤

  1. 加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring-aop的依赖,使用注解必须使用spring-aop依赖
  2. 在类中加入spring的注解(多个不同功能的注解)
  3. 在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置
<context:component-scan base-package="包名"/>
  1. 使用注解创建对象, 创建容器ApplicationContext

首先还是创建一个新的项目,在pom.xml文件中加入依赖

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
</dependency>

二、@Component

首先创建学生类

package com.md.b1;

import org.springframework.stereotype.Component;

/**
 * @author MD
 * @create 2020-08-08 15:51

 * @Component: 创建对象的, 等同于<bean>的功能
  *     属性:value 就是对象的名称,也就是bean的id值,
  *          value的值是唯一的,创建的对象在整个spring容器中就一个
  *     位置:在类的上面
  *
  *  @Component(value = "myStudent")等同于
 *   <bean id="myStudent" class="com.bjpowernode.ba01.Student" />
 */


//@Component(value = "myStudent")

//    省略value,常用

@Component("myStudent")

//    不指定对象的名称,由spring默认提供:为类名首字母小写(student)
//@Component
public class Student {

    private String name;
    private Integer age;

    public Student() {
        System.out.println("我是Student的无参构造方法");
    }

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

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

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

    <!--声明组件扫描器,组件就是java对象
        base-package:指定注解在你项目中的包名
        component-scan工作方式:spring会扫描遍历base-package指定的包,
                                找包中以及子包中的所有的类,并找到类中的注解,
                                按照注解的功能创建对象,或者给属性赋值
    -->


   <context:component-scan base-package="com.md.b1"/>

</beans>

测试:

package com.md;

import com.md.b1.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author MD
 * @create 2020-08-08 16:05
 */
public class MyTest01 {
    @Test
    public void test01(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 从容器中获取对象
        Student student = (Student) ac.getBean("myStudent");
        System.out.println(student);
    }
}

注意一:指定多个包的三种方式

    <!--第一种方式:使用多次组件扫描器,指定不同的包-->
    <context:component-scan base-package="com.md.b1"/>
    <context:component-scan base-package="com.md.b2"/>

    <!--第二种方式:使用分隔符(;或,)分隔多个包名-->
    <context:component-scan base-package="com.md.b1;com.md.b2" />

    <!--第三种方式:指定父包-->
    <context:component-scan base-package="com.md" />

重点:

注意二:spring中和@Component功能一致,创建对象的注解还有

  1. @Repository(用在持久层类的上面) : 放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的
  2. @Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的
  3. @Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果。

以上三个注解的使用语法和@Component一样的。 都能创建对象,但是这三个注解还有额外的功能

@Repository,@Service,@Controller是给项目的对象分层的

某个类使用上面的三个注解都不合适的时候使用@Component

问题:创建对象的注解有几个,为什么有多个?

三、@Value

简单类型属性注入,需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值

使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上

如下:

package com.md.b2;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 * @author MD
 * @create 2020-08-08 15:51
 */
@Component("myStudent")
public class Student {
    /**
     * @Value: 简单类型的属性赋值
     *   属性: value 是String类型的,表示简单类型的属性值
     *   位置: 1.在属性定义的上面,无需set方法,推荐使用。
     *         2.在set方法的上面
     */

//    @Value(value = "比比东")
    @Value("比比东")
    private String name;

//    @Value(value = "18")
    @Value("22")
    private Integer age;

    public Student() {
        System.out.println("我是Student的无参构造方法");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

然后在spring的配置文件中applicationContext.xml加入组件扫描器

 <context:component-scan base-package="com.md.b2"/>

测试

 @Test
    public void test01(){

        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 从容器中获取对象

        Student student = (Student) ac.getBean("myStudent");
        System.out.println(student);
//我是Student的无参构造方法
//Student{name='比比东', age=22}
}

四、@Autowired

byType自动注入

@Autowired:spring框架提供的注解,实现引用类型的赋值

需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式(byType)

package com.md.b3;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author MD
 * @create 2020-08-08 16:39
 */

@Component("student")
public class Student {
    @Value("比比东")
    private String name;

    @Value("20")
    private Integer age;

    /**
     * 引用数据类型
     * @Autowired:spring框架提供的注解,实现引用类型的赋值
     * spring中通过注解给引用数据类型赋值的原理是使用自动注入,支持byName,byType
     * 默认使用的byType默认注入
     *
     * 使用:在属性定义的上面,无需set方法,推荐
     *       在set方法的上面
     */

// 使用注解在School类里定义对象名称,以及属性值 或 使用bean的方式创建对象以及通过set方法给属性赋值
    @Autowired
    private School school;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}

School类

package com.md.b3;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 * @author MD
 * @create 2020-08-08 16:40
 */
@Component("mySchool")
public class School {

    @Value("交大")
    private String name;
    @Value("上海")
    private String address;

    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

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

然后在spring的配置文件中applicationContext.xml加入组件扫描器

 <context:component-scan base-package="com.md.b3"/>

测试和上面一样,就不写了,除了使用注解还可以使用xml的方式

这样就是可以的,

 <bean id="school" class="com.md.b3.School">
        <property name="name" value="上海交通大学"/>
        <property name="address" value="上海"/>
    </bean>

五、@Qualifier

byName自动注入

由于@Autowired 默认使用的是byType,为了使用byName方式,

需要在引用属性上联合使用注解@Autowired 与@Qualifier

@Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值,

使用byName方式
1. 属性的上面加入@Autowired注解
2. 属性的上面加@Qualifier(value="bean的id")注解,表示使用指定名称的bean完成赋值
     也就是使用这个对象来完成赋值

School类

@Component("school")
public class School {

    @Value("厦门大学")
    private String name;
    @Value("厦门")
    private String address;

    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

Student类

@Component("student")
public class Student {


    @Value("比比东")
    private String name;

    @Value("20")
    private Integer age;


// 在School类里通过注解直接对象名为school
    @Autowired
    @Qualifier("school")
    private School school;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }

}

属性:required ,是一个boolean类型的,默认true

  • required=true:表示引用类型赋值失败,程序报错,并终止执行。推荐使用
  • required=false:引用类型如果赋值失败, 程序正常执行,引用类型是null

例如:还是在上面的程序上

使用的是byName的方式,而此时失误bean的id写错了

  • 若使用默认值,则结果或报错
  • 若按照下面写的执行,则不会报错,但数据为空
@Component("student")
public class Student {

    @Value("比比东")
    private String name;

    @Value("20")
    private Integer age;

// 在School类里通过注解直接对象名为school
    @Autowired(required = false)
    @Qualifier("schoo")
    private School school;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}


六、@Resource

spring提供了对jdk中@Resource注解的支持。

@Resource注解既可以按名称匹配Bean,也可以按类型匹配 Bean。 默认是按名称注入(byName)

使用该注解,要求 JDK 必须是 6 及以上版本,@Resource 可在属性上,也可在 set 方法上

还是School类中

@Component("school")
public class School {

    @Value("浙江大学")
    private String name;
    @Value("浙江")
    private String address;


    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

}

此时Student类

@Component("student")
public class Student {

    @Value("比比东")
    private String name;

    @Value("20")
    private Integer age;


    /**
     * 引用类型
     * @Resource: 来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值
     *            使用的也是自动注入原理,支持byName, byType .默认是byName
     *  位置: 1.在属性定义的上面,无需set方法,推荐使用。
     *        2.在set方法的上面
     */
    //默认是byName: 先使用byName自动注入,如果byName赋值失败,再使用byType
    //@Resource

    // 若只使用byName方式,需要增加一个属性 name,name的值就是bean的id(对象名称)
    @Resource(name = "school")
    private School school;


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }

}


在spring的配置文件中applicationContext.xml加入组件扫描器

   <context:component-scan base-package="com.md.b6"/>

测试:

   @Test
    public void test01(){

        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 从容器中获取对象

        Student student = (Student) ac.getBean("student");
        System.out.println(student);

//       Student{name='比比东', age=20, school=School{name='浙江大学', address='浙江'}}
    }

七、XML和注解对比

注解优点是:方便、直观、高效(代码少,没有配置文件的书写那么复杂)

缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的

适合于不是经常修改的

XML 方式优点是:配置和代码是分离的、在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载

缺点:编写麻烦,效率低,大型项目过于复杂

posted @ 2020-08-10 22:23  山丘i  阅读(270)  评论(0编辑  收藏  举报