简洁大气蓝色文章资讯网站,wordpress下一篇,公司页面图片,网站建设费入什么总账科目文章目录 一. 配置扫描路径二. 使用注解储存Bean对象1. 使用五大类注解储存Bean2. 为什么要有五大类注解#xff1f;3.4有关获取Bean参数的命名规则 三. 使用方法注解储存Bean对象1. 方法注解储存对象的用法2. Bean的重命名 在前一篇博客中#xff08;
Spring项目创建与Bean… 文章目录 一. 配置扫描路径二. 使用注解储存Bean对象1. 使用五大类注解储存Bean2. 为什么要有五大类注解3.4有关获取Bean参数的命名规则 三. 使用方法注解储存Bean对象1. 方法注解储存对象的用法2. Bean的重命名 在前一篇博客中
Spring项目创建与Bean的存储与读取(DL)介绍的是通过配置文件注册对象从而存储到 Spring 中这种方式其实还是挺繁琐的。 实际上在使用学习使用 Spring过程中当我们要实现一个功能的时候先应该考虑的是有没有相应的注解是实现对应功能的Spring 中很多功能的配置都是可以依靠注解实现的而本篇中介绍的是使用注解来存储 Bean 对象。
一. 配置扫描路径
首先还是要创建 Spring 项目这里有问题还是去看我上一篇博客。当创建好项目后我们的第一步就是配置扫描路径这一步骤非常关键的这里错了之后的的操作就都不会生效了。
我们在resources目录下创建一个spring-config.xml配置文件用来设置扫描的路径在配置文件中添加如下内容
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contenthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsdcontent:component-scan base-package/content:component-scan
/beans其中content:component-scan base-package/content:component-scan里面 base-package的值设置为你需要扫描对象的根路径这个路径从java目录开始比如我在如图中的com.tr.demo目录下创建类 那么这个配置文件中根路径就为com.tr.demo所以我们将base-package的值设置为com.tr.demo。
content:component-scan base-packagecom.tr.demo/content:component-scan二. 使用注解储存Bean对象
想要使用注解那得先知道能使用哪些注解在 Spring 中有五大类注解和方法注解分别为
五大类注解Controller控制器、Service服务、Repository仓库、Component组件、Configuration配置。方法注解Bean。
1. 使用五大类注解储存Bean
首先我们来了解如何使用五大类注解来储存对象先以Controller注解为例我们有如下的代码
package com.tr.demo;import org.springframework.stereotype.Controller;Controller
public class UserController {public void sayHi() {System.out.println(Hi, UserController~);}
}像这样在扫描路径下创建类并在类上加上Controller注解就将Bean存储到容器当中了。
接下来就要从 Spring 中读取出我们的对象这里还是先使用依赖查找的方式来获取 Bean使用五大类注解默认情况下Bean 的名字就是原类名首字母小写小驼峰。
import com.tr.demo.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class APP {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);//获取对象时使用类名的小驼峰形式作为 name 参数UserController userController context.getBean(userController, UserController.class);userController.sayHi();}
}运行结果 要注意是使用了五大类注解创建的类且类必须要在前面我们配置的扫描路径下包括子包才能将 Bean 存储到 Spring 当中否则是无效的所以这个扫描路径也叫做根路径。
设置根路径其实也是为了提高程序的性能因为如果不设置根路径Spring 就会扫描项目文件中所有的目录但并不是所有类都需要储存到 Spring当中这样性能就会比较低设置了根路径Spring 就只扫描该根路径下所有的目录就可以了提高了程序的性能。
上面只使用了 Controller那么我们再来验证一下其他四个注解可不可以达到同样的目的同时为了验证上面的结论我们在com.tr.demo目录下再创建一个inner目录在根路径外在创建一个类Student使用类注解。 package com.tr.demo.inner;
import org.springframework.stereotype.Component;Component
public class UserComponent {public void sayHi() {System.out.println(Hi, UserComponent~);}
}package com.tr.demo.inner;
import org.springframework.context.annotation.Configuration;Configuration
public class UserConfiguration {public void sayHi() {System.out.println(Hi, UserConfiguration~);}
}package com.tr.demo.inner;
import org.springframework.stereotype.Repository;Repository
public class UserRepository {public void sayHi() {System.out.println(Hi, UserRepository~);}
}package com.tr.demo.inner;
import org.springframework.stereotype.Service;Service
public class UserService {public void sayHi() {System.out.println(Hi, UserService~);}
}import com.tr.demo.UserController;
import com.tr.demo.inner.UserComponent;
import com.tr.demo.inner.UserConfiguration;
import com.tr.demo.inner.UserRepository;
import com.tr.demo.inner.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class APP {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);//获取对象时使用类名的小驼峰形式作为 name 参数UserController userController context.getBean(userController, UserController.class);userController.sayHi();UserService service context.getBean(userService, UserService.class);service.sayHi();UserConfiguration configuration context.getBean(userConfiguration, UserConfiguration.class);configuration.sayHi();UserComponent component context.getBean(userComponent, UserComponent.class);component.sayHi();UserRepository repository context.getBean(userRepository, UserRepository.class);repository.sayHi();}
}运行结果
五大类注解效果都是一样的而不在根路径下的Student是无效的。
还需要知道的是使用注解存储的 Bean 和使用XML存储的的 Bean 是可以一同使用的比如我们将将刚刚有问题的Student重新通过XML的方式进行存储。 运行结果 2. 为什么要有五大类注解
既然都五大类完成的是同样的工作那为什么要有五大类注解呢
其实五大类注解主要是为了规范 Java 项目的代码Java 项目的标准分层如下
控制层Controller服务层Service数据持久层Dao
而五大类注解便是对应着不同的层级别使用的让程序猿看到某一个注解就可以明确这个了类是做什么的。 Controller控制器校验用户请求数据的正确性安保系统直接和前端打交道校验前端发来请求是参数和合法性。 Service服务编排和调度具体执行方法的客服中心不会直接操作数据库根据请求判断具体调用哪个方法。 Repository数据持久层直接和数据库交互实际业务的执行也叫DAO层data access object。 Component组件工具类层为整个项目存放一些需要使用的组件但又和其他层没有什么实际交互。 Configuration 配置项项目中的一些配置。 包括企业中也是按照这样的结构来将项目分层的典型的比如阿里它只是在标准分层在服务层Service做了一个扩展划分的更加细致详细了。 五大类注解主要起到的是“见名知意”的作用代码层面上来看作用是类似的我们去查看五大类类注解的源码看一看。 可以看到五大类的源码中除了 Component 以外其他四大类注解中都包含了 Component 注解的功能这四大类注解都是基于 Component 实现的是 Component 拓展。
3.4有关获取Bean参数的命名规则
上文中在使用依赖查找的方式获取Bean时getBean方法的BeanName是使用类名的小驼峰形式即类名的首字母小写这是因为使用注解储存对象时默认会将类名的小驼峰形式设置为 Bean 的名字但并不是完全依照这个规则的是有特殊情况的。
比如我们创建一个类将它的前两个字母大写如UConfig此时来看使用类名的小驼峰形式还能不能获取到 Bean。
package com.tr.demo;import org.springframework.stereotype.Repository;Repository
public class UConfig {public void sayHi(){System.out.println(Hi, UConfig~);}
}启动类
import com.tr.demo.UConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class APP2 {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);UConfig uConfig context.getBean(uConfig, UConfig.class);uConfig.sayHi();}
}运行结果 可以看到程序报错了说没有找到beanName为uConfig的对象那此时的beanName是什么呢
此时再来试一下原本的类名大驼峰看能不能获取
UConfig uConfig context.getBean(UConfig, UConfig.class);运行结果 此时就获取到了好像多少有点玄学在里面我们来翻一翻源码看一看这是什么原因。
双击Shift进行全局搜索上面是根于对象名称来找到对象的所以我们输入beanName试着搜索一下 我们会发现有AnnotationBeanNameGenerator类与BeanNameGenerator接口那我们就试着点到AnnotationBeanNameGenerator类源码看一看。
正常点开后看到的应该是 IDEA 将.class文件反编译出来的代码缺少注释和明确的变量命名。 我们点击Download Sources将 Spring 源码下载下来即可此时我们在在源码中就能看到下面的方法看名字也知道用来建立默认的BeanName的。 返回值是Introspector.decapitalize方法的返回值再点进去看看这个方法。 此时我们就能分析得出结论如果类名长度大于1并且满足第一个与第二个字母为大写则构造的BeanName就为原类名其他正常情况为类名的小驼峰形式这就解释了UConfig类的BeanName为什么是原类名了。 而且我们会发现这个方法所在类是来自于jdk的。
所以BeanName的规范命名规则并不是 Spring 独创的而依照 Java 标准库的规则进行的。
如果类名不存在或类名为空字符串BeanName为原类名。如果类名字长度大于1且第一个与第二个字符为大写BeanName为原类名。其他情况BeanName为原类名的小驼峰形式。
三. 使用方法注解储存Bean对象
1. 方法注解储存对象的用法
五大类注解是添加到某个类上的而方法注解是放到方法上的当一个方法返回的是一个具体的实例对象时我们就可以使用方法注解Bean来将对象储存到 Spring但是单单使用一个Bean是不能够成功储存对象的还需要在方法所在类上使用五大类注解才行比如搭配一 个Component 注解方法注解是不能够单独使用的Bean注解必须要搭配五大类注解一起使用Spring为了提升性能所做的规定毕竟造方法的成本太低了不能去扫描整个项目的方法吧。
还是要注意使用必须是在根路径下。
比如我们有一个普通文章的实体类ArticleInfo
package com.tr.demo.model;import java.time.LocalDateTime;/*** 普通的文章实体类*/
public class ArticleInfo {private int aid;private LocalDateTime createtime;private String title;private String author;private String content;public void setAid(int aid) {this.aid aid;}public void setCreatetime(LocalDateTime createtime) {this.createtime createtime;}public void setTitle(String title) {this.title title;}public void setAuthor(String author) {this.author author;}public void setContent(String content) {this.content content;}Overridepublic String toString() {return ArticleInfo{ aid aid , createtime createtime \n , title title \ , author author \ \n , content content \ };}
}下面演示使用Bean方法注解储存对象
package com.tr.demo;import com.tr.demo.model.ArticleInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import java.time.LocalDateTime;Controller
public class Articles {Bean// 将当前方法返回的对象存储到 IoC 容器public ArticleInfo getArt(){// 伪代码实际上这里的 Bean 不是 new 出来的ArticleInfo articleInfo new ArticleInfo();articleInfo.setAid(1);articleInfo.setCreatetime(LocalDateTime.now());articleInfo.setTitle(夏日绝句);articleInfo.setAuthor(李清照);articleInfo.setContent(生当做人杰死亦为鬼雄。至今思项羽不肯过江东。);return articleInfo;}public void sayHi(){System.out.println(Hi, Articles~);}
}获取方法注解储存的对象时传入的BeanName参数值默认值就是方法名我上面的代码中方法名为getArt所以获取时就使用getArt作为参数来进行获取。
import com.tr.demo.model.ArticleInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class APP3 {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);ArticleInfo article context.getBean(getArt, ArticleInfo.class);System.out.println(article);}
}运行结果
2. Bean的重命名
获取方法注解储存的对象时传入的BeanName参数值默值为方法名但像上面那样返回对象的方法名称往往是getXXX这样式取名的虽然在语法与实现上是没有问题的但实际开发写出这样的代码看起来还是比较别扭的。
实际上注解 Bean 是可以加参数的给储存的对象起别名像下面这个样子。
Controller
public class Articles {Bean(article)// 将当前方法返回的对象存储到 IoC 容器public ArticleInfo getArt(){// 伪代码实际上这里的 Bean 不是 new 出来的ArticleInfo articleInfo new ArticleInfo();articleInfo.setAid(1);articleInfo.setCreatetime(LocalDateTime.now());articleInfo.setTitle(夏日绝句);articleInfo.setAuthor(李清照);articleInfo.setContent(生当做人杰死亦为鬼雄。至今思项羽不肯过江东。);return articleInfo;}public void sayHi(){System.out.println(Hi, Articles~);}
}也可以给 Bean 设置多个别名总结起来有如下几种方式
//方式一(省略参数名的情况下默认是name)
Bean(article1)
//方式二
Bean(name article2)
//方式三
Bean(value article3)
//起多个别名
Bean(name {article4, article5})
Bean(value {article6, article7})
Bean({article8, article9, article10})我们按照第 9 行的方式设置此时获取方法注解储存的对象就能够使用别名来进行获取。 import com.tr.demo.model.ArticleInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class APP4 {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);ArticleInfo article1 context.getBean(article6, ArticleInfo.class);System.out.println(article1);System.out.println(-----------------------------------------------------);ArticleInfo article2 context.getBean(article7, ArticleInfo.class);System.out.println(article2);System.out.println(-----------------------------------------------------);}
}运行结果
再想一下当一个 Bean 有别名了那使用之前那个方法名还能够获取到对象吗尝试一下
import com.tr.demo.model.ArticleInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class APP5 {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);ArticleInfo article context.getBean(getArt, ArticleInfo.class);System.out.println(article);}
}运行结果
此时就能发现是获取不到的 所以使用 Bean 存储对象的beanName命名规则是当没有设置name/value属性时此时 Bean 的默认名字就是方法名一旦添加了别名name/value属性后就只能通过重命名的别名来获取 Bean 了默认的使用方法名获取 Bean 对象就不能使用了。
还要简单注意一下Bean 使用时同一类如果多个 Bean 使用相同的名称此时程序执行是不会报错的他会根据类加载顺序和类中代码从上至下的的顺序将第一个 Bean 存放到 Spring 中但第一个之后的对象就不会被存放到容器中了也就是只有在第一次创建 Bean 的时候会将对象和 Bean 名称关联起来后续再有相同名称的Bean存储时候容器会自动忽略。
还可以通过类注解 Order 注解控制类加载顺序值越小优先级越高进而影响 Bean 的存放的先后顺序这些也比较简单就不做演示了。