Spring05_基于注解的IOC和DI

本教程源码请访问:tutorial_demo

在学习基于注解的IOC和DI之前,大家要有一个基本的认识,即注解配置和之前学习的XML配置要实现的功能是一样的,都是为了降低程序间的耦合,只是配置的形式不一样

一、使用注解实现IOC

1.1、创建项目

  1. 在Idea中新建Maven工程;
  2. 工程创建完成后添加相应的坐标。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.codeaction</groupId>
    <artifactId>anno</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
    </dependencies>
</project>

1.2、添加相关类

1.2.1、创建持久层接口

package org.codeaction.dao;

public interface IAccountDao {
    void saveAccount();
}

1.2.2、创建持久层接口实现类

package org.codeaction.dao.impl;

import org.codeaction.dao.IAccountDao;

//@Component
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
    @Override
    public void saveAccount() {
        System.out.println("账户保存成功");
    }
}

@Component和@Repository注解下面会讲。

1.2.3、创建业务层接口

package org.codeaction.service;

public interface IAccountService {
    void saveAccount();
}

1.2.4、创建业务层接口实现类

package org.codeaction.service.impl;

import org.codeaction.dao.IAccountDao;
import org.codeaction.dao.impl.AccountDaoImpl;
import org.codeaction.service.IAccountService;

//@Component
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    private IAccountDao accountDao;
    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

@Component

作用:把资源让Spring来管理,相当于在XML中配置了一个bean;

属性:只有一个value属性,用来指定id。如果不指定value属性,默认bean的id是当前类的类名,首字母小写。

@Controller、@Service、@Repository

作用和属性与@Component完全一样,但是它们提供了更加明确的语义。

@Controller:用于视图层的注解

@Service:用于业务层的注解

@Repository:用于持久层的注解

1.3、添加XML配置文件

XML文件在resource目录下。这个文件也可以不写,但是不写如何配置,后面的教程会讲

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 告知spring创建容器时要扫描的包 -->
    <context:component-scan base-package="org.codeaction"></context:component-scan>
</beans>

1.4、添加测试类

创建带有main方法的类,用来进行测试

package org.codeaction.ui;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.codeaction.service.impl.AccountServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AccountUI {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        IAccountService accountService = (IAccountService) context.getBean("accountService");
        IAccountDao accountDao = (IAccountDao) context.getBean("accountDao");

        System.out.println(accountService);
        System.out.println(accountDao);
    }
}

运行main方法,控制台输出如下:

org.codeaction.service.impl.AccountServiceImpl@5f71c76a
org.codeaction.dao.impl.AccountDaoImpl@1d7acb34

通过上面的内容,我们学习了如何通过注解配置bean,在AccountServiceImpl中,accountDao属性没有被注入值,接下来我们学习一下如何注入值,也就是使用注解实现DI。

二、使用注解实现DI

2.1、修改业务层接口实现类

package org.codeaction.service.impl;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao accountDao;
    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

@Autowired

作用

  1. 自动按照类型注入;
  2. 当使用此注解注入属性时,set方法可以省略,它只能注入bean类型;
  3. 当有多个类型匹配时(2.3会讲这种情况),使用要注入的对象变量名称作为bean的id,在Spring容器中查找,找到了可以注入成功,找不到就报错。

2.2、修改测试类

package org.codeaction.ui;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.codeaction.service.impl.AccountServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AccountUI {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        IAccountService accountService = (IAccountService) context.getBean("accountService");
        IAccountDao accountDao = (IAccountDao) context.getBean("accountDao");

        System.out.println(accountService);
        System.out.println(accountDao);
        
        accountService.saveAccount();
    }
}

运行main方法,控制台输出如下:

org.codeaction.service.impl.AccountServiceImpl@1188e820
org.codeaction.dao.impl.AccountDaoImpl@2f490758
11111111111111111111111111111

2.3、自动类型注入多个类型匹配的情况

2.3.1、新增业务层接口实现类

package org.codeaction.dao.impl;

import org.codeaction.dao.IAccountDao;
import org.springframework.stereotype.Repository;

@Repository("accountDao1")
public class AccountDaoImpl1 implements IAwccountDao {
    @Override
    public void saveAccount() {
        System.out.println("222222222222222222222222");//注意这个打印输出
    }
}

运行2.2中的main方法,控制台输出如下:

org.codeaction.service.impl.AccountServiceImpl@33b37288
org.codeaction.dao.impl.AccountDaoImpl@77a57272
11111111111111111111111111111

大家注意,这里输出了“11111111111111111111111111111”,证明@Autowired自动注入在有多个类型匹配时,使用要注入的对象变量名称作为bean的id,如果存在,依然可以注入成功。如果此时我希望注入AccountDaoImpl1的对象应该如何做呢?

2.3.2、注入特定id的bean对象(方式1)

修改业务层接口实现类,代码如下:

package org.codeaction.service.impl;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    @Qualifier("accountDao1")
    private IAccountDao accountDao;
    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

运行2.2中的main方法,控制台输出如下:

org.codeaction.service.impl.AccountServiceImpl@77a57272
org.codeaction.dao.impl.AccountDaoImpl@7181ae3f
222222222222222222222222

这里输出了“222222222222222222222222”,证明我们使用@Autowired结合 @Qualifier实现了特定id的bean对象的注入。

@Qualifier

作用

  1. 在自动按照类型注入的基础之上,再按照bean的id注入;
  2. 给方法注入参数;
  3. 在给属性注入时,不能独立使用,必须和@Autowired一起使用(我们目前案例讲的就是这种情况),给方法注入参数时,可以独立使用。

属性:只有一个value,指定bean的id。

上面的案例要使用两个注解,能不能一个注解就搞定?

2.3.3、注入特定id的bean对象(方式2)

修改业务层接口实现类,代码如下:

package org.codeaction.service.impl;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    //@Autowired
    //@Qualifier("accountDao1")
    @Resource(name = "accountDao1")
    private IAccountDao accountDao;
    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

运行2.2中的main方法,控制台输出如下:

org.codeaction.service.impl.AccountServiceImpl@77a57272
org.codeaction.dao.impl.AccountDaoImpl@7181ae3f
222222222222222222222222

这里输出了“222222222222222222222222”,证明我们使用@Resource实现了特定id的bean对象的注入。

@Resource

作用:直接按照bean的id注入,只能注入bean类型。

属性:name,指定bean的id。

2.3.4、注入基本数据类型和String类型

package org.codeaction.service.impl;

import org.codeaction.dao.IAccountDao;
import org.codeaction.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    @Value("hello world")
    private String test;

    //@Autowired
    //@Qualifier("accountDao1")
    @Resource(name = "accountDao1")
    private IAccountDao accountDao;
    @Override
    public void saveAccount() {
        System.out.println(this.test);
        accountDao.saveAccount();
    }
}

运行2.2中的main方法,控制台输出如下:

org.codeaction.service.impl.AccountServiceImpl@3e77a1ed
org.codeaction.dao.impl.AccountDaoImpl@3ffcd140
hello world
100
222222222222222222222222

这里输出了“hello world”和“100”,证明我们使用@Value能够注入基本数据类型和String类型。

@Value

作用:注入基本数据类型和 String 类型数据的。
属性:只有一个value,用于指定值 。

三、其他注解

3.1、@Scope

作用:指定bean的作用范围。

属性:value,用来指定范围,可以取的值包括,singleton、prototype、request、session、globalsession。

3.2、@PostConstruct

作用:用于指定初始化方法。

3.3、@PreDestroy

作用:用于指定销毁方法。

原文地址:https://www.cnblogs.com/codeaction/p/12976135.html