Spring框架四、Spring IOC注解使用

在之前的项目中,我们都是通过xml文件进行bean或者某些属性的赋值,其实还有另外一种注解的方式,在企业开发中使用的很多,在bean上添加注解,可以快速的将bean注册到ioc容器。

一、使用注解的方式注册bean到IOC容器中

1、使用介绍

如果想要将自定义的bean对象添加到IOC容器中,需要在类上添加某些注解Spring中包含4个主要的组件添加注解:

  1. @Controller:控制器,推荐给controller层添加此注解。
  2. @Service:业务逻辑,推荐给业务逻辑层添加此注解。
  3. @Repository:仓库管理,推荐给数据访问层添加此注解。
  4. @Component:给不属于以上基层的组件添加此注解。

注意:我们虽然人为的给不同的层添加不同的注解,但是在spring看来,可以在任意层添加以上任意注解。spring底层是不会给具体的层次验证注解,这样写的目的只是为了提高可读性,最偷懒的方式就是给所有想交由IOC容器管理的bean对象添加component注解。

使用注解需要如下步骤:

  1. 添加上述四个注解中的任意一个。
  2. 添加自动扫描注解的组件,此操作需要依赖context命名空间。
  3. 添加自动扫描的标签context:component-scan。

注意:当使用注解注册组件和使用配置文件注册组件是一样的,但是要注意:

  • 组件的id默认就是组件的类名首字符小写,如果非要改名字的话,直接在注解中添加即可。如:@Controller(value = “bobo”),那么组件的id就被改为“bobo”。
  • 组件默认情况下都是单例的,如果需要配置多例模式的话,可以在注解下添加@Scope注解。

2、练习

ioc.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
        http://www.springframework.org/schema/context/spring-context.xsd"
        >
    <!--
    定义自动扫描的基础包:
    base-package:指定扫描的基础包,spring在启动的时候会将基础包及子包下所有加了注解的类都自动
                扫描进IOC容器
    -->
    <context:component-scan base-package="com.bobo"></context:component-scan>
</beans>

PersonController.java

package com.bobo.controller;

import org.springframework.stereotype.Controller;

@Controller
public class PersonController {
}

PersonService.java

package com.bobo.service;

import org.springframework.stereotype.Service;

@Service
public class PersonService {
}

PersonDao.java

package com.bobo.dao;

import org.springframework.stereotype.Repository;

@Repository
public class PersonDao {
}

测试类

import com.bobo.controller.PersonController;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context=new ClassPathXmlApplicationContext("ioc.xml");
        System.out.println(context.getBean("personController"));
        System.out.println(context.getBean("personService"));
        System.out.println(context.getBean("personDao"));
    }
}

运行输出:

com.bobo.controller.PersonController@6ab7a896
com.bobo.service.PersonService@327b636c
com.bobo.dao.PersonDao@45dd4eda

二、定义扫描包时要包含的类和不要包含的类

当定义好基础的扫描包后,在某些情况下可能要有选择性的配置是否要注册bean到IOC容器中,此时可以通过如下的方式进行配置。
ioc.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
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.bobo" use-default-filters="false">
        <!--
        当定义好基础扫描的包之后,可以排除包中的某些类,使用如下的方式:
        type:表示指定过滤的规则
            annotation:按照注解进行排除,标注了指定注解的组件不要,expression表示要过滤的注解
            assignable:指定排除某个具体的类,按照类排除,expression表示不注册的具体类名
            aspectj:后面讲aop的时候说明要使用的aspectj表达式,不用
            custom:定义一个typeFilter,自己写代码决定哪些类被过滤掉,不用
            regex:使用正则表达式过滤,不用
        -->
<!--        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->

        <!--指定只扫描哪些组件,默认情况下是全部扫描的,所以此时要配置的话需要在component-scan标签中添加 use-default-filters="false"-->
        <context:include-filter type="assignable" expression="com.bobo.service.PersonService"/>
    </context:component-scan>
</beans>

三、使用@AutoWired进行自动注入

1、自动注入例子

PersonDao.java

package com.bobo.dao;

import org.springframework.stereotype.Repository;

@Repository
public class PersonDao {
    public void getPerson(){
        System.out.println("我是波波");
    }
}

PersonService.java

package com.bobo.service;

import com.bobo.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PersonService {
    @Autowired
    private PersonDao personDao;

    public void getPerson(){
        personDao.getPerson();
    }
}

PersonController.java

package com.bobo.controller;

import com.bobo.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class PersonController {
    @Autowired
    private PersonService personService;

    public void getPerson() {
        personService.getPerson();
    }
}

单元测试

public class MyTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioc.xml");
        PersonController personController = applicationContext.getBean("personController", PersonController.class);
        personController.getPerson();
    }
}

运行输出

我是波波

2、AutoWired注解规则

当使用AutoWired注解的时候,自动装配的时候是根据类型实现的。

  1. 如果只找到一个,则直接进行赋值。
  2. 如果没有找到,则直接抛出异常。
  3. 如果找到多个,那么会按照变量名作为id继续匹配,如果匹配上直接进行装配,否则匹配不上则直接报异常。

PersonService.java

package com.bobo.service;

import com.bobo.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PersonService {
    @Autowired
    private PersonDao personDao;

    public void getPerson(){
        System.out.println("PersonService");
        personDao.getPerson();
    }
}

PersonServiceSon.java

package com.bobo.service;

import com.bobo.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PersonService {
    @Autowired
    private PersonDao personDao;

    public void getPerson(){
        System.out.println("PersonService");
        personDao.getPerson();
    }
}

PersonController.java

package com.bobo.controller;

import com.bobo.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class PersonController {
    @Autowired
    private PersonService personServiceSon;

    public void getPerson() {
        personServiceSon.getPerson();
    }
}

单元测试

public class MyTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioc.xml");
        PersonController personController = applicationContext.getBean("personController", PersonController.class);
        personController.getPerson();
    }
}

运行输出

PersonServiceSon
我是波波

实际上注入的是:PersonServiceSon。

3、@Qualifier注解

还可以使用@Qualifier注解来指定id的名称,让spring不要使用变量名,当使用@Qualifier注解的时候也会有两种情况:1、找到,则直接装配。2、找不到,就会报错。

修改PersonControll.java加上@Qualifer注解,指定id为persionService

package com.bobo.controller;

import com.bobo.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

@Controller
public class PersonController {
    @Autowired
    @Qualifier("personService")
    private PersonService personServiceSon;

    public void getPerson() {
        personServiceSon.getPerson();
    }
}

单元测试

public class MyTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioc.xml");
        PersonController personController = applicationContext.getBean("personController", PersonController.class);
        personController.getPerson();
    }
}

输出结果

PersonService
我是波波

四、@AutoWired可以进行定义在方法上

当我们查看@AutoWired注解的源码的时候发现,此注解不仅可以使用在成员变量上,也可以使用在方法上。

1、当方法上有@AutoWired注解时:

  • 此方法在bean创建的时候会自动调用。
  • 这个方法的每一个参数都会自动注入值。

修改PersonService.java

package com.bobo.service;

import com.bobo.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PersonService {
    @Autowired
    private PersonDao personDao;

    public void getPerson(){
        System.out.println("PersonService");
        personDao.getPerson();
    }
    public PersonService(){
        System.out.println("PersonService被创建");
    }
    @Autowired
    public void test(PersonDao personDao){
        System.out.println("personDao:"+personDao);
    }
}

单元测试

public class MyTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioc.xml");
    }
}

运行输出

PersonService被创建
personDao:com.bobo.dao.PersonDao@290d210d

2、@Qualifier注解也可以作用在属性上,用来被当作id去匹配容器中的对象,如果没有 此注解,那么直接按照类型进行匹配

package com.bobo.service;

import com.bobo.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class PersonService {
    @Autowired
    private PersonDao personDao;

    public void getPerson(){
        System.out.println("PersonService");
        personDao.getPerson();
    }
    
    @Autowired
    public void test(PersonDao personDao){
        System.out.println("personDao:"+personDao);
    }

    public void test1(@Qualifier("personServiceSon") PersonService personService){
        personService.getPerson();
    }
}

五、自动装配的注解@AutoWired,@Resource

在使用自动装配的时候,出了可以使用@AutoWired注解之外,还可以使用@Resource注解,大家需要知道这两个注解的区别。

  1. @AutoWired:是spring中提供的注解,@Resource:是jdk中定义的注解,依靠的是java的标准。
  2. @AutoWired默认是按照类型进行装配,默认情况下要求依赖的对象必须存在,@Resource默认是按照名字进行匹配的,同时可以指定name属性。
  3. @AutoWired只适合spring框架,而@Resource扩展性更好。
package com.bobo.controller;

import com.bobo.dao.PersonDao;
import com.bobo.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class PersonController {

    @Qualifier("personService")
    @Resource
    private PersonService personServiceSon;

    public PersonController() {
        System.out.println("PersonController构造函数");
    }

    public void getPerson(){
        System.out.println("personController:"+personServiceSon);
        personServiceSon.getPerson();
    }

    /**
     * 当方法上有@AutoWired注解时:
     *  1、此方法在bean创建的时候会自动调用
     *  2、这个方法的每一个参数都会自动注入值
     * @param personDao
     */
    @Autowired
    public void test(PersonDao personDao){
        System.out.println("test:"+personDao);
    }

    /**
     * @Qualifier注解也可以作用在属性上,用来被当作id去匹配容器中的对象,如果没有
     * 此注解,那么直接按照类型进行匹配
     * @param personService
     */
    @Autowired
    public void test2(@Qualifier("personServiceSon") PersonService personService){
        System.out.println("test2:"+personService);
    }
}

单元测试

public class MyTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioc.xml");
        applicationContext.getBean("personController", PersonController.class).getPerson();
    }
}

运行输出:

PersonController构造函数
test:com.bobo.dao.PersonDao@197d671
test2:com.bobo.service.PersonServiceSon@6a01e23
personController:com.bobo.service.PersonServiceSon@6a01e23
PersonServiceSon
我是波波

六、泛型依赖注入

Teacher.java

package com.bobo.bean;

public class Teacher {
}

Student.java

package com.bobo.bean;

public class Student {
}

BaseDao.java

package com.bobo.dao;

public abstract class BaseDao<T> {
    public abstract void save();
}

TeacherDao.java

import com.bobo.bean.Teacher;
import org.springframework.stereotype.Repository;

@Repository
public class TeacherDao extends BaseDao<Teacher> {
    public void save() {
        System.out.println("保存老师");
    }
}

StudentDao.java

import com.bobo.bean.Student;
import org.springframework.stereotype.Repository;

@Repository
public class StudentDao extends BaseDao<Student> {
    public void save() {
        System.out.println("保存学生");
    }
}

BaseService.java

package com.bobo.service;

import com.bobo.dao.BaseDao;
import org.springframework.beans.factory.annotation.Autowired;

public class BaseService<T> {
    @Autowired
    BaseDao<T> baseDao;

    public void save() {
        System.out.println("自动注入对象:" + baseDao);
        baseDao.save();
    }
}

TeacherService.java

package com.bobo.service;

import com.bobo.bean.Teacher;
import org.springframework.stereotype.Service;

@Service
public class TeacherService extends BaseService<Teacher> {

}

StudentService.java

package com.bobo.service;

import com.bobo.bean.Student;
import org.springframework.stereotype.Service;

@Service
public class StudentService extends BaseService<Student> {
}

单元测试

import com.bobo.service.StudentService;
import com.bobo.service.TeacherService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioc.xml");

        TeacherService teacherService = applicationContext.getBean("teacherService", TeacherService.class);
        teacherService.save();

        StudentService studentService = applicationContext.getBean("studentService", StudentService.class);
        studentService.save();
    }
}

运行输出

自动注入对象:com.bobo.dao.TeacherDao@2a32de6c
保存老师
自动注入对象:com.bobo.dao.StudentDao@7692d9cc
保存学生
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃透Java

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值