侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 748 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

Spring注解驱动开发(4)之组件注入

zze
zze
2018-02-12 / 0 评论 / 0 点赞 / 658 阅读 / 15771 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

@AutoWired

@Autowired 将会自动从 IoC 容器中查找与标注属性同类型的 bean 注入, 如果容器中有多个相同类型的 bean,将会注入 id 与 属性名相同的那个 bean。

示例

1、创建测试 Dao:

// com.springanno.dao.UserDao

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
}

2、创建测试 Service:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    /**
     * 默认情况下,如果容器中没有该属性类型对应的 bean,那么将会抛出异常
     * 可通过指定 @Autowired 的属性 required = false 让此次的自动装配不必须,此时容器中如果不存在该类型 bean 就不会抛出异常
     */
    @Autowired(required = false)
    private UserDao userDao;

    public void printDao() {
        System.out.println(userDao);
    }
}

3、使用注解扫描包:

// com.springanno.config.MainConfig
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.springanno")
public class MainConfig {
}

4、测试:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService);
userService.printDao();
/*
com.springanno.service.UserService@60dcc9fe
com.springanno.dao.UserDao@222114ba
 */

@Autowired 不仅可以用在属性上,还可以用在方法上:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private UserDao userDao;
    /*
    将会从容器中找到与参数类型相同的 bean 传入来执行该方法
     */
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void printDao() {
        System.out.println(userDao);
    }
}

也可以标注在构造器上:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private UserDao userDao;
    /*
    将会从容器中找到与参数类型相同的 bean 传入来执行该构造器来创建 UserService 实例
     */
    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public void printDao() {
        System.out.println(userDao);
    }
}

不仅如此,还可以标注在参数上:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private UserDao userDao;
    /*
    将会从容器中找到与参数类型相同的 bean 传入来执行该构造器来创建 UserService 实例
     */
    public UserService(@Autowired UserDao userDao) {
        this.userDao = userDao;
    }

    public void printDao() {
        System.out.println(userDao);
    }
}

如果当前组件只有一个有参构造器, @Autowired 可以省略不写:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private UserDao userDao;
    /*
    当前组件只有一个有参构造器
    将会从容器中找到与参数类型相同的 bean 传入来自动执行该构造器来创建 UserService 实例
     */
    public UserService (UserDao userDao) {
        this.userDao = userDao;
    }

    public void printDao() {
        System.out.println(userDao);
    }
}

通过 @Bean 标注方法注册 bean 时,该方法的参数也会默认从容器中获取,看如下示例:

// com.springanno.dao.UserDao
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public UserDao(){}
}
// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void printDao() {
        System.out.println(userDao);
    }
}
// com.springanno.config.MainConfig

import com.springanno.dao.UserDao;
import com.springanno.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.springanno")
public class MainConfig {

    @Bean("userService2")
    public UserService userService(UserDao userDao){
        UserService userService = new UserService();
        userService.setUserDao(userDao);
        return userService;
    }
}
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService2");
UserDao userDao = applicationContext.getBean(UserDao.class);
userService.printDao();
System.out.println(userDao);
/*
com.springanno.dao.UserDao@21507a04
com.springanno.dao.UserDao@21507a04
*/

@Qualifier

可以通过 @Qualifier@Autowired 搭配使用来指定此次要装配 bean 的 id

示例

1、创建测试 Dao:

// com.springanno.dao.UserDao
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public UserDao(){}
}

2、创建测试 Service:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Qualifier("userDao")  // 指定装配 id 为 userDao 的 bean
    @Autowired
    private UserDao userDao;

    public void printDao(){
        System.out.println(userDao);
    }
}

3、配置包扫描:

// com.springanno.config.MainConfig
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.springanno")
public class MainConfig {

}

4、测试:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService);
userService.printDao();
/*
com.springanno.service.UserService@60dcc9fe
com.springanno.dao.UserDao@222114ba
 */

@Primary

@Primary 也是用来对自动装配进行控制的,他用来指定当容器中存在多个类型相同的 bean 时,自动装配优先装配哪个 bean,和 @Bean 一起使用。当然,它不能和 @Qualifier 同时使用。

示例

1、创建测试 Dao:

// com.springanno.dao.UserDao
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public UserDao(){}
}

2、创建测试 Service:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void printDao(){
        System.out.println(userDao);
    }
}

3、配置包扫描:

// com.springanno.config.MainConfig
import com.springanno.dao.UserDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
@ComponentScan("com.springanno")
public class MainConfig {

    @Primary // id 为 userDao2 的 bean 优先装配
    @Bean
    public UserDao userDao2() {
        return new UserDao();
    }
}

4、测试:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService);
userService.printDao();
UserDao userDao = (UserDao) applicationContext.getBean("userDao2");
System.out.println(userDao);
/*
com.springanno.service.UserService@3b2da18f
com.springanno.dao.UserDao@5906ebcb
com.springanno.dao.UserDao@5906ebcb
 */

@Resource

@Resource 注解(JSR250 中定义)相当于 @Autowired@Qualifier 注解一起使用,既能完成自动装配,也能指定要装配 bean 的 id,不支持 @Primary 注解。

示例

1、创建测试 Dao:

// com.springanno.dao.UserDao
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public UserDao(){}
}

2、创建测试 Service:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService {

    @Resource(name = "userDao2")
    private UserDao userDao;

    public void printDao(){
        System.out.println(userDao);
    }
}

3、配置包扫描并注册另一个 Dao 到容器:

// com.springanno.config.MainConfig
import com.springanno.dao.UserDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.springanno")
public class MainConfig {

    @Bean
    public UserDao userDao2() {
        return new UserDao();
    }
}

4、测试:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService);
userService.printDao();
UserDao userDao = (UserDao) applicationContext.getBean("userDao2");
System.out.println(userDao);
/*
com.springanno.service.UserService@2d9d4f9d
com.springanno.dao.UserDao@4034c28c
com.springanno.dao.UserDao@4034c28c
 */

@Inject

@Inject 注解(JSR330 中定义)使用与 @Autowired 注解一致,只是没有属性,作用比较单一。

示例

1、创建测试 Dao:

// com.springanno.dao.UserDao
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public UserDao(){}
}

2、创建测试 Service:

// com.springanno.service.UserService
import com.springanno.dao.UserDao;
import org.springframework.stereotype.Service;

import javax.inject.Inject;

@Service
public class UserService {

    /*
    与 Autowired 相同,需导包
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>com.springsource.javax.inject</artifactId>
        <version>1.0.0</version>
    </dependency>
     */
    @Inject
    private UserDao userDao;

    public void printDao() {
        System.out.println(userDao);
    }
}

3、配置包扫描:

// com.springanno.config.MainConfig

import com.springanno.dao.UserDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
@ComponentScan("com.springanno")
public class MainConfig {
    @Primary
    @Bean
    public UserDao userDao2() {
        return new UserDao();
    }
}

4、测试:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService);
userService.printDao();
UserDao userDao = (UserDao) applicationContext.getBean("userDao2");
System.out.println(userDao);
/*
com.springanno.service.UserService@2aa5fe93
com.springanno.dao.UserDao@5c1a8622
com.springanno.dao.UserDao@5c1a8622
*/

@AutowiredSpring 定义的,而 @Resource@Inject 是 Java 规范中定义的。

实现 Aware 接口

本内容其实不属于 Spring 注解驱动的内容,只是它也涉及了组件注入的知识,就放这里一起说了。

如果我们自定义的组件想要使用 Spring 容器底层的一些组件,例如 ApplicationContextBeanFactory 等,可以让自定义组件实现相应的 Aware 接口,Spring 容器启动时会通过接口的回调给我们注入相应的组件。

1、创建测试 Service:

// com.springanno.service.UserService
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;


@Service("testUserServer")
public class UserService implements ApplicationContextAware, BeanNameAware, EnvironmentAware {

    public void setBeanName(String beanName) {
        System.out.println(beanName);
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext.getBean("testUserServer"));
    }

    public void setEnvironment(Environment environment) {
        System.out.println(environment);
    }
}

2、配置包扫描:

// com.springanno.config.MainConfig
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.springanno")
public class MainConfig {

}

3、测试:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
/*
testUserServer
StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[MapPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]}
com.springanno.service.UserService@3f56875e
 */

下面是 Spring 提供的继承了 Aware 接口的类:

ApplicationEventPublisherAware (org.springframework.context)
NotificationPublisherAware (org.springframework.jmx.export.notification)
MessageSourceAware (org.springframework.context)
BeanFactoryAware (org.springframework.beans.factory)
EnvironmentAware (org.springframework.context)
EmbeddedValueResolverAware (org.springframework.context)
ResourceLoaderAware (org.springframework.context)
ImportAware (org.springframework.context.annotation)
LoadTimeWeaverAware (org.springframework.context.weaving)
BeanNameAware (org.springframework.beans.factory)
BeanClassLoaderAware (org.springframework.beans.factory)
ApplicationContextAware (org.springframework.context)
0

评论区