资讯专栏INFORMATION COLUMN

Spring基于Annotation的依赖注入小结

adam1q84 / 2619人阅读

摘要:设想在未来我们为的构造函数新增字段那么上述代码将修改为如果的初始化耗时很长,将影响构造函数的后续初始化工作。上述在构造函数里直接初始化的过程,属于主动初始化依赖对象,二者耦合度高,不方便测试。调用方使用对进行依赖注入。

  最近接触了几个比较大的Java项目,其中常常存在Bean之间的依赖,例如在某服务启动前要初始化各类词典,主要方式有显式声明Bean和隐式注解注入2种,本文着重介绍后一种。

1. 依赖注入简介

  首先我们定义“依赖”是什么:如果在Class A中有Class B的实例,则称A依赖B。
现在我们来构造一个依赖:

public class UserDao {
    DBConnection conn;
    
    public UserDao() {
        // 先初始化数据库连接
        conn = new DBConnection();
    }
}

上述代码中,UserDao即对DBConnection存在依赖。但这样构造依赖存在如下问题:
(1) 耦合度高。设想在未来我们为DBConnection的构造函数新增字段name,那么上述代码将修改为:
conn = new DBConnection();
conn = new DBConnection(String name);
(2) 如果DBConnection的初始化耗时很长,将影响构造函数的后续初始化工作。

上述UserDao在构造函数里直接初始化DBConnection的过程,属于主动初始化依赖对象,二者耦合度高,不方便测试。如果被依赖对象事先就初始化好了,直接供给本Class调用,则称之为依赖注入。例如上述代码可改写为如下:

public class UserDao {
    @Autowired  //依赖注入
    DBConnection conn;
    public UserDao() {
    }
}

要使注入生效,我们还需要在DBConnection中添加Bean标识Component

@Component //将类标识为Bean
public class DBConnection {
    public DBConnection() {
        init(); //初始化工作
    }
}

同时,为了让Bean的标识被探测到,我们还需要在xml配置文件中添加自动扫描:

到此处相信读者大致了解其注入原理:

将一些初始化词典、数据库连接的类添加诸如@Component的标识,使之成为Bean。

Spring做自动扫描记录下这些Bean。

调用方使用@Autowired对Bean进行依赖注入。
此处我将这3步分别命名为:服务Bean化、自动扫描、依赖注入。接下来我将详细介绍这3部分。

2. 服务Bean化

  事实上我们可以在任何情况下使用@Component标识需要被"Bean化"的服务。但不久我们会发现,其他更有水平的代码里会有更多富于变化的标识,例如:@Repository@Service@Controller。这是怎么回事?设想我们现在有加载本地词典的类A,本地词典监控类B,二者有明显区别:前者的功能视数据访问,后者则是监控服务,我们更愿意对标识做更精细化的区分,具体如下:
  @Repository是为DAO(数据访问)特制的声明,将一个类声明为Repository意味着该类主要功能是数据读取、DB访问。
  @Service则声明该类为服务性质的Bean,例如上文中的词典监控服务,还有许多无关数据操作的功能性初始化类,都应该被标识为Service
  @Controller声明标志着一个类是SpringWeb的MVC控制器,主要负责MVC之间的操纵。另一个类似的声明是@RequestMapping,将URL映射为一个方法。

以上3个新的声明均为@Component的子集,因此仅仅使用@Component也不影响后续的扫描和注入过程。但在现实生活中,其实只有很少的场合我们需要用到@Component,例如无法给类做清晰的定位时。

3. 注解扫描

注意到上文中的这段自动扫描,它的包名其实可以根据用户需求做出更改。例如:现在我有一个判断query是否为脏词的服务A,它依赖注入了自动加载脏词词典的类B。此外,项目中还存在访问数据库的类C,但我们没有为数据库配置访问信息。当我们将注解扫描范围设置为整个项目时,启动服务A将产生问题。

解决方案是缩小自动扫描范围,使得Spring仅扫描B而不扫描C。具体做法是增加扫描过滤器, Spring支持正则Regex和AspectJ两种表达式的方式进行扫描过滤。
例如:


    
    

上面的xml配置就成功的扫描名为com.example.service.dictionary的package而忽略了以org.example.service.db为前缀的package。

4. 依赖注入

@Autowired:负责自动装配被成功扫描的Bean。
@Qualifier("xxxxx"): 有时候我们有参数不同的两个相同类的bean需要装配(具体为什么会存在这种现象?可想象要连接2个数据库。),那么如何多带带指定我需要装配哪一个呢?@Qualifier配合@Autowired可用于消除这类歧义。

在方法内部,我们也有一些"注解":
@PostConstruct@PreDestroy是Bean内分别执行初始化和销毁bean的注解。b>注意!它并不属于Spring,而是属于J2ee里的jar包,因此使用时需要在xml配置:

@PostConstruct: 初始化bean
@preDestroy: 结束前清理。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67467.html

相关文章

  • 慕课网_《使用Google Guice实现依赖注入》学习总结

    摘要:时间年月日星期六说明本文部分内容均来自慕课网。慕课网教学源码学习源码第一章课程介绍课程简介是啥读音是轻量级的依赖注入框架说明一个的框架需要有基础什么是剥离注入轻量级代码少易维护性能优异,跟比较。 时间:2017年10月14日星期六说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com 教学源码:https://github.com/zccodere/s......

    2450184176 评论0 收藏0
  • 手写Spring之DI依赖注入

    摘要:如感兴趣,可移步手写之基于动态创建对象手写之基于注解动态创建对象今天将详细介绍如何手写依赖注入,在运行过程中如何动态地为对象的属性赋值。完成后在中会有相关的包出现进行注入前需要创建工厂,在运行时从工厂中取出对象为属性赋值。 前两篇文章介绍了关于手写Spring IOC控制反转,由Spring工厂在运行过程中动态地创建对象的两种方式。如感兴趣,可移步: 手写Spring之IOC基于xml...

    Cruise_Chan 评论0 收藏0
  • Spring核心 面向切面 AOP

    摘要:下图展示了这些概念的关联方式通知切面的工作被称为通知。切面在指定的连接点被织入到目标对象中。该注解表明不仅仅是一个,还是一个切面。 在软件开发中,散布于应用中多处的功能被称为横切关注点(crosscutting concern)。通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往会直接嵌入到应用的业务逻辑之中)。把这些横切关注点与业务逻辑相分离正是面向切面编程(AOP...

    Winer 评论0 收藏0
  • 第一章--Spring之旅

    摘要:两种方式来表示的应用上下文。日志,事务管理和安全这样的系统服务经常融入到具有核心业务逻辑的组件中去,这些系统服务通过被称为横切关注点。容器使用管理构成应用的组件,他会创建相互协作的组件之间的关联。的生命周期四俯瞰的风景线模块,,,, 完整代码请见:https://github.com/codercuixi...为了降低Java开发的复杂性,Spring采用了以下4种策略: 基于poj...

    pkwenda 评论0 收藏0
  • SpringBoot基础篇AOP之基本使用姿势小结

    摘要:通知和切点共同定义了关于切面的全部内容,它是什么时候,在何时和何处完成功能引入允许我们向现有的类添加新的方法或者属性组装方面来创建一个被通知对象。这可以在编译时完成例如使用编译器,也可以在运行时完成。和其他纯框架一样,在运行时完成织入。 原文:190301-SpringBoot基础篇AOP之基本使用姿势小结 一般来讲,谈到Spring的特性,绕不过去的就是DI(依赖注入)和AOP(切...

    timger 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<