写点什么

关于 Spring 注解开发教程,打包全送你

发布于: 34 分钟前

​​​​​​​​​​摘要:spring 是我们 web 开发中必不可少的一个框架,基于传统的 xml 方式配置 bean 总觉得太过繁琐,从 spring2.5 之后注解的出现可以大大简化我们的配置。


本文分享自华为云社区《如何高效提升Java开发效率—Spring注解开发全套教程!》,作者: 灰小猿。

一、使用注解标识组件


为了不再在 IOC 中一个个的声明类对象,首先根据每一个类的功能的不同,Spring 中先规定了基于组件的注解,大致可以分为以下四种:


①普通组件:@Component

标识一个受 Spring IOC 容器管理的组件,我们也可以理解为是除了数据库层、业务逻辑层、控制层组件以外的其他组件使用的注解。


②持久化层组件:@Respository

标识一个受 Spring IOC 容器管理的持久化层组件,一般就是用来标注数据库层


③业务逻辑层组件:@Service

标识一个受 Spring IOC 容器管理的业务逻辑层组件


④表述层控制器组件:@Controller

标识一个受 Spring IOC 容器管理的表述层控制器组件。


同时这几个注解后面也可以添加一些参数,比如比较常用的一个是注解的括号中加 value 属性,来表示这个组件在容器中的 ID,如果不设置 value 值时,默认的 ID 是类名的全称(第一个字母小写)。


如下实例,我们为一个 Dao 层组件添加一个 @Respository 注解


/** * 数据库层注解 * */@Repositorypublic class BookDao {    public void saveBook() {        System.out.println("bookDao中的图书已保存...");    }}
复制代码


通过这四个注解我们首先就可以将所有的组件逐一分类。置于为什么要使用注解进行分类,说到底其实就是为了方便方便快速的知道哪一个类是做了什么类型的功能,同时方便之后通过这四个注解将组件加入到 IOC 容器中。


所以你也可以把这四个注解理解为是 Spring 分发给不同功能组件的一个“身份证”,只有拥有这四种“身份证”,那么这个组件就可以被加入到 IOC 容器中。


在这里有一点需要注意:事实上 Spring 并没有能力识别一个组件到底是不是它所标记的类型,即使将 @Respository 注解用在一个表述层控制器组件上面也不会产生任何错误,所以 @Respository、@Service、@Controller 这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色。方便将组件加入到容器中去。

二、组件扫描

1、普通扫描


现在倒是对所有的组件进行了详细的分类,但是这样就等于将所有的组件已经加入到 IOC 容器中了嘛?如果真的是这样的话,那么我们就真正的实现了低代码时代了...


所以现在我们就是应该如何将拥有注解标识的组件加入到 IOC 容器中呢?在这里 Spring 在 IOC 中提供了一个包扫描的功能,通过这个名字我们就可以知道,Spring 可以自动的扫描整个项目中被标记了这四个注解的组件,并且将其加入到 IOC 容器中。


进行包扫描的具体操作是这样的:


进行包扫描依赖于 Context 名称空间,所以需要在 IOC 中加入该名称空间,加入名称空间的方法有两种,一种是在 IOC 的头文件中加入如下代码:


xmlns:context="http://www.springframework.org/schema/context"
复制代码


但是因为这种不好记所以不推荐,还有一种就是直接在界面点击下方的 Namespaces,在其中找到并勾选 Context



在容器中进行包扫描的代码是:


<context:component-scan base-package="com.spring"></context:component-scan>
复制代码


其中 base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包及其子包中的所有类。当需要扫描多个包时可以使用逗号分隔。如上面的代码就是扫描 com.spring 包下面的所有类。

2、包含与排除特定组件


但是这样进行扫描的范围有时候未免还是有一些大,那么能不能再缩小进行包扫描的范围呢?当然是可以的。


如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类,如:


<context:component-scan base-package="com.atguigu.component" resource-pattern="autowire/*.class"/>
复制代码


(1)扫描包含特定组件


如果我们仅仅是想要扫描包含特定特征的组件,那么我们可以如下方法:

context:include-filter 子节点表示要包含的目标类


但是需要注意的是:由于 context:component-scan 默认是将所有的类全部都添加进去,所以在此基础上再添加是没有用的,需要在 context:component-scan 中加入属性参数 use-default-filters,use-default-filters="true"表示默认将所有的类都添加进去,false 表示将所有的类都不添加进去,如下代码表示仅仅扫描包含 include-filter 中所指特征的组件,其中的 type 用来表示使用何种类型的扫描表达式,expression 后面跟表达式。


<context:component-scan base-package="com.spring" use-default-filters="false">    <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/></context:component-scan>
复制代码


(2)扫描排除特定组件


尽然有扫描包含特定组件,那么就有扫描排除特定组件,

context:exclude-filter 子节点表示要排除在外的目标类。


以下代码表示扫描除以下特征外的其他组件。


<context:component-scan base-package="com.spring">    <context:exclude-filter type="assignable" expression="com.spring.service.BookService"/>  </context:component-scan> 
复制代码


同时 component-scan 下可以拥有若干个 include-filter 和 exclude-filter 子节点,来表示可以包含多个哪种特征的组件或排除具有哪种特征的组件。


关于上面说到的 type 中填写的过滤表达式类型及作用如下表:



最常用的上面两个,以下三个几乎不用:

type="aspectj" aspectj 表达式

type="custom"定义一个 TypeFile,自己写一个类定义使用哪一个

type="regex"利用正则表达式


注意有 bug:有些小伙伴们在进行注解开发的时候注解和扫描都写的很完美,可就是不起作用,原因可能是缺少相应特有的一个 jar 包,在这里需要导入额外的一个 aop 包

spring-aop-4.0.0.RELEASE.jar


到这里,将组件添加到容器中的操作就算是完成了,在我们将组件添加成功之后呢,我们可以在组件图标的右上角看到一个小 S 的图标,这个时候就表示这个组件已经成功的加入到了容器中

3、实现注解的三步骤


总结一下实现注解的三步骤:


1.   添加 context 依赖      context:component-scan


2.   为类添加相应的注解


3.   导入 aop 包        spring-aop-4.0.0.RELEASE.jar


三、组件自动装配


但是这样就结束了嘛?就这么轻松了嘛?之前学习的 bean 的作用域与生命周期这些都没用了嘛?当然不是!!!更重要的是组件还没获取呢!!!


那么接下来就来和大家讲一下使用注解开发的高端操作,让你知道使用注解是多么的香!!!


我们平常在使用类的时候,难免会在类中调用其他自定义的类对吧,就比如说,Controller 组件中往往需要用到 Service 组件的实例,Service 组件中往往需要用到 Repository 组件的实例。


那么如果我们对这些需要实例化的组件一个一个的在类中进行实例化,是不是就显得太麻烦了呢?哎,聪明机智的程序员们怎么会没有想到这一点呢!所以组件的自动装配就出现了,在 spring 中我们可以通过注解的形式来对组件进行自动的装配,那么到底如何对组件进行装配的呢?


其实是这样的,在 IOC 中指定要扫描的包时,context:component-scan 元素会自动注册一个 bean 的后置处理器:AutowiredAnnotationBeanPostProcessor 的实例。该后置处理器可以自动装配标记了 @Autowired、@Resource 或 @Inject 注解的属性。


而上面的 @Autowired、@Resource 或 @Inject 这三个注解,就是我们在进行组件的自动装配时最常用的注解,下面我和大家介绍一下这三种注解的具体使用。

1、@autowired 注解


@autowired 注解能够根据类型实现自动装配。无论是构造器、普通字段(即使是非 public)、还是一切具有参数的方法都可以应用 @Autowired 注解


默认情况下,所有使用 @Autowired 注解的属性都需要被设置。当 Spring 找不到匹配的 bean 装配属性时,会抛出异常。


(1)@autowired 装配原理


接下里我来和大家详细的讲一下 @autowired 注解的装配原理:


1、使用自动装配时,首先会根据类型去容器中查找相应的组件,这就类似于 getBean("bookService.class")


2、如果没有找到就抛异常,如果找到一个就赋值


3、如果找到多个,那么也是有一定的装配依据的,并不是随便找一个进行装配。


首先根据属性名作为 ID 进行继续寻找,找到对应属性名的组件就进行装配,没有找到就报错,报错的原因是:使用变量名作为 id 进行匹配时候,没有找到对应的属性名


(2)@Qualifier 指定装配 ID


对于这种报错其实还有一种解决:就是使用 @Qualifier("bookService")指定查找 ID,找到就装配,找不到报错,指定查找 ID 的代码示例如下:


// 添加注解表示自动装填@Autowired@Qualifier("bookdao")private BookDao bookDao;
复制代码


(3)required—装配报错解决


那么要是每次找不到就报错,这样程序不是就崩了吗?对于这样的情况应该怎么办呢?其实还有一种解决办法,解决找不到报错:使用 required 参数

@Autowired(required=false)        required=false 表示如果实在找不到,就装配 null

反正装配的依据就是,按照多种规则查找合适的装配对象,直到查找成功,实在不成功就返回 null。


(4)特殊属性的自动装配


上面是使用 @Autowired 注解的基本原理与步骤,我们直到 spring 的注解开发是十分强大的,下面我们再来说几个特殊的属性的装配。


@Autowired 注解可以应用在数组类型的属性上,此时 Spring 将会把所有匹配的 bean 进行自动装配。


@Autowired 注解也可以应用在集合属性上,此时 Spring 读取该集合的类型信息,然后自动装配所有与之兼容的 bean。


@Autowired 注解用在 java.util.Map 上时,若该 Map 的键值为 String,那么 Spring 将自动装配与值类型兼容的 bean 作为值,并以 bean 的 id 值作为键。


这样一来,@Autowired 注解的自动装配是不是就显得十分的强大了,以后妈妈再也不用担心我 new 对象了!!!​

2、@Resource 注解


@Resource 注解要求提供一个 bean 名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为 bean 的名称。

3、@Inject 注解


@Inject 和 @Autowired 注解一样也是按类型注入匹配的 bean,但没有 reqired 属性。


以上就是进行自动装配时使用的三个注解,在这里再总结一下,

@autoWried 是 spring 自带的,更强大一些,能够实现 required=false

@Resource 也是 java 自带的,扩展性更强,所以如果切换成另一个容器框架,@Resource 还是可以用的,而 @Inject 和 @Autowired 注解一样也是按类型注入匹配的 bean,但没有 reqired 属性。其实在日常开发中,我们最常用到的、功能最强大的注解还是 @Autowired 注解。所以记住这一个基本上就可以了。


然后再总结一下使用注解的好处,主要就是节省了 new 对象时麻烦,直接使用一个 @Autowired 注解,spring 就可以自动的为该属性赋值,一般来说将组件加入到 IOC 的注解和 @Autowired 是结合使用的。

四、注解使用的小细节


其实在使用注解进行开发时还有一些小细节需要注意,我在这里给大家总结一下。

1、整合多个配置文件


当我们开发时的项目过大的时候,在一个配置文件写如配置有时候就不能满足我们的需求,所以 Spring 允许通过<import>将多个配置文件引入到一个文件中,进行配置文件的集成。这样在启动 Spring 容器时,仅需要指定这个合并好的配置文件就可以。import 元素的 resource 属性支持 Spring 的标准的路径资源


如下示例,我们有 springmvc.xml 和 spring.xml 两个配置文件,现在我们想要将 spring.xml 引入到 springmvc.xml 中,方法是:在 springmvc.xml 中写入下面代码:


<import resource="spring.xml"/>
复制代码


2、路径书写问题


对于 spring 中常用地址书写,有时候需要使用 classpath,而有时候又需要其他,针对不同的路径书写,有不一样的含义和使用:具体看下表:



3、获取组件时的问题


对于使用注解方法添加到容器中的组件,我们在 IOC 容器中是看不到的,那么获取它的时候应该如何获取呢?


我们上面也说了,在注解中不指定 id 的前提下,spring 是会自动的为每一个组件设置一个第一个字母小写的组件的全称作为 ID,(如 Book 类的 ID 默认是 book)。在容器中获取组件的方法和以往一样,但是如果是单实例的话,一般建议以类为参数进行获取。如:


Book book = (Book)ioc.getBean(Book.class);
复制代码


五、写在最后


以上就是 Spring 注解开发的全部知识点了,是不是觉得使用注解开发比原生代码简洁多了,注解也是 SSM 框架乃至之后开发会经常用到的东西。


点击关注,第一时间了解华为云新鲜技术~

发布于: 34 分钟前阅读数: 3
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
关于Spring注解开发教程,打包全送你