Spring框架主要包括IoC和AOP,这两大功能都可以使用注解进行配置。

开发环境:IntelliJ IDEA 2019.2.2
Spring Boot版本:2.1.8
新建一个名称为demo的Spring Boot项目。

一、bean定义

在 Spring 中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。
bean是一个由Spring IoC容器实例化、组装和管理的对象。
使用@Component、@Service或@Configuration注解来修饰一个类,这些类会被Spring自动检测并注册到容器中,在类里面使用@Bean注解修

饰的方法,会被视为一个bean存放到Spring容器中。

下面例子实现了怎样根据类型获取bean的名称,获取bean;

1、新建类 MyBean.java

  1. package com.example.demo;
  2.  
  3. public class MyBean {
  4.  
  5. public MyBean(String id){
  6. this.id = id;
  7. }
  8.  
  9. private String id;
  10.  
  11. public String getId() {
  12. return id;
  13. }
  14.  
  15. public void setId(String id) {
  16. this.id = id;
  17. }
  18. }

2、新建类 MyConfig.java

  1. package com.example.demo;
  2.  
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5.  
  6. @Configuration
  7. public class MyConfig {
  8.  
  9. //默认bean的名称为方法名,即下面的getMyBean
  10. @Bean
  11. public MyBean getMyBean(){
  12. return new MyBean("1");
  13. }
  14.  
  15. //设置bean的名称为bean
  16. @Bean("bean2")
  17. public MyBean getMyBean2(){
  18. return new MyBean("2");
  19. }
  20. }

3、修改启动类代码 DemoApplication.java

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9.  
  10. @SpringBootApplication
  11. @RestController
  12. public class DemoApplication {
  13.  
  14. public static void main(String[] args) {
  15. SpringApplication.run(DemoApplication.class, args);
  16. }
  17.  
  18. @Autowired
  19. ApplicationContext ctx;
  20.  
  21. @RequestMapping(value = "/")
  22. public String index(){
  23. //根据类型获取bean的名称
  24. String[] names = ctx.getBeanNamesForType(MyBean.class);
  25. for(String name : names){
  26. System.out.println(name);
  27. }
  28.  
  29. //获取bean
  30. MyBean bean1 = (MyBean)ctx.getBean("getMyBean");
  31. System.out.println(bean1.getId());
  32.  
  33. MyBean bean2 = (MyBean)ctx.getBean("bean2");
  34. System.out.println(bean2.getId());
  35.  
  36. return "";
  37. }
  38. }

运行项目后,浏览器访问:http://localhost:8080/,IDEA控制台输出:
getMyBean
bean2
1
2

项目结构

二、依赖注入

使用注解可以实现实例的注入,最常用的是@Resource及@Autowired。
@Resource是JSR-250定义的注解,默认会根据名称进行注入。
@Autowired默认会根据类型进行注入。

1、继续使用上面例子的两个类 MyBean.java、MyConfig.java

2、修改启动类代码 DemoApplication.java

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8.  
  9. import javax.annotation.Resource;
  10.  
  11. @SpringBootApplication
  12. @RestController
  13. public class DemoApplication {
  14.  
  15. public static void main(String[] args) {
  16. SpringApplication.run(DemoApplication.class, args);
  17. }
  18.  
  19. //使用@Resource注入
  20. @Resource(name="getMyBean")
  21. MyBean myBean1;
  22.  
  23. //使用@Autowired注入
  24. @Autowired
  25. MyBean bean2;
  26.  
  27. @RequestMapping(value = "/")
  28. public String index(){
  29. System.out.println(myBean1.getId());
  30. System.out.println(bean2.getId());
  31. return "";
  32. }
  33. }

浏览器访问:http://localhost:8080/,IDEA控制台输出:
getMyBean
bean2
1
2

备注:
上面MyBean bean2的bean2不能修改为别的名称。原因:
@Autowired根据类型进行注入,如果容器中只有一个MyBean类型的bean,则bean2可以随便命名。
但本例子容器中有两个MyBean类型的bean,碰到这种有多个bean的情况,则根据属性名来查找,这里属性名bean2最终会找到相应的bean。
如果把MyBean bean2改成MyBean myBean2,则运行时IEAD控制台会报异常信息:

  1. Field myBean2 in com.example.demo.DemoApplication required a single bean, but 2 were found:
  2. - getMyBean: defined by method 'getMyBean' in class path resource [com/example/demo/MyConfig.class]
  3. - bean2: defined by method 'getMyBean2' in class path resource [com/example/demo/MyConfig.class]

以上例子的注入方式为设值注入,还可以使用构造注入,向控制器的构造器中注入bean。
修饰构造器只能使用@Autowired注解,@Resource不能修改构造器。
例子:

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8.  
  9. import javax.annotation.Resource;
  10.  
  11. @SpringBootApplication
  12. @RestController
  13. public class DemoApplication {
  14.  
  15. public static void main(String[] args) {
  16. SpringApplication.run(DemoApplication.class, args);
  17. }
  18.  
  19. MyBean bean2;
  20.  
  21. //构造注入
  22. @Autowired
  23. public DemoApplication(MyBean bean2){
  24. this.bean2 = bean2;
  25. }
  26.  
  27. @RequestMapping(value = "/")
  28. public String index(){
  29. System.out.println(bean2.getId());
  30. return "";
  31. }
  32. }

三、使用Primary注解

根据类型来注入,如果容器中存在多个相同类型的bean时,会抛异常,因为此时Spring不知道将哪个bean注入。
针对这个问题,可以使用@Primary注解。

1、修改MyConfig.java代码,为第一个bean增加注解@Primary

  1. package com.example.demo;
  2.  
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.context.annotation.Primary;
  6.  
  7. @Configuration
  8. public class MyConfig {
  9.  
  10. //默认bean的名称为方法名,即下面的getMyBean
  11. @Bean
  12. @Primary
  13. public MyBean getMyBean(){
  14. return new MyBean("1");
  15. }
  16.  
  17. //设置bean的名称为bean
  18. @Bean("bean2")
  19. public MyBean getMyBean2(){
  20. return new MyBean("2");
  21. }
  22. }

2、启动类代码 DemoApplication.java还是用上面例子

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8.  
  9. import javax.annotation.Resource;
  10.  
  11. @SpringBootApplication
  12. @RestController
  13. public class DemoApplication {
  14.  
  15. public static void main(String[] args) {
  16. SpringApplication.run(DemoApplication.class, args);
  17. }
  18.  
  19. //使用@Resource注入
  20. @Resource(name="getMyBean")
  21. MyBean myBean1;
  22.  
  23. //使用@Autowired注入
  24. @Autowired
  25. MyBean bean2;
  26.  
  27. @RequestMapping(value = "/")
  28. public String index(){
  29. System.out.println(myBean1.getId());
  30. System.out.println(bean2.getId());
  31. return "";
  32. }
  33. }

浏览器访问:http://localhost:8080/,IDEA控制台输出:
1
1

四、Scope注解

配置bean时可以指定bean的作用域(scope),一般的bean可以配置为单态(singleton)或者非单态(prototype)。
配置为singleton,Spring的bean工厂只返回同一个bean的实例。
配置为prototype,则每次会创建一个新的实例。

1、修改代码 MyConfig.java

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9.  
  10. import javax.annotation.Resource;
  11.  
  12. @SpringBootApplication
  13. @RestController
  14. public class DemoApplication {
  15.  
  16. public static void main(String[] args) {
  17. SpringApplication.run(DemoApplication.class, args);
  18. }
  19.  
  20. @Autowired
  21. ApplicationContext ctx;
  22.  
  23. @RequestMapping(value = "/")
  24. public String index(){
  25. String s = "prototype:" + ctx.getBean("bean1") + "<br /> "
  26. + "singleton:" + ctx.getBean("bean2") + "<br /> ";
  27. return s;
  28. }
  29. }

浏览器访问:http://localhost:8080/,多次刷新,页面内容都变化:
prototype:com.example.demo.MyBean@6fce7ec4
singleton:com.example.demo.MyBean@7626c5f9
prototype:com.example.demo.MyBean@357b01f6
......

注意:
如果在一个单态的bean里面注入一个非单态的bean,则这个单态的bean所维护的非单态bean实例,将不会被刷新。
例子Spring MVC的控制器是单态的,如果往控制器里面注入一个非单态的bean,如下所示:

  1. //注入一个非单态的bean
  2. @Autowired
  3. private MyBean bean1;
  4.  
  5. @RequestMapping(value = "/")
  6. public String index(){
  7. return bean1.toString();
  8. }

浏览器访问:http://localhost:8080/,多次刷新,页面都是显示如下:
com.example.demo.MyBean@5d0c61c9
说明index()方法输出的MyBean都是调用同一个实例,因为控制器在初始化时,就已经被注入了一个bean,而且一直维护着同一个实例。

五、方法注入

如果在一个单态的bean里面注入一个非单态的bean,则这个单态的bean所维护的非单态bean实例,将不会被刷新。
有两种简单的解决方法:
1、在需要注入的一方(单态的bean),直接使用ApplicationContext,每次调用非单态的bean,都由容器返回。

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7.  
  8. @RestController
  9. public class DemoController {
  10.  
  11. @Autowired
  12. private ApplicationContext ctx;
  13.  
  14. private MyBean getBean1(){
  15. return (MyBean)ctx.getBean("bean1");//一个非单态的bean
  16. }
  17.  
  18. @RequestMapping(value = "/")
  19. public String index(){
  20. return getBean1().toString();
  21. }
  22. }

浏览器访问:http://localhost:8080/,多次刷新,页面每次都变化:
com.example.demo.MyBean@12a7cacc
com.example.demo.MyBean@1776b0ea
......

2、使用Spring的方法注入。
使用@Lookup注解来修饰一个抽象方法,该方法会返回bean的实例。
下面代码运行结果和上面使用ApplicationContext一样。

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Lookup;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6.  
  7. @RestController
  8. public abstract class DemoController {
  9. @Lookup("bean1")
  10. public abstract MyBean createBean() ;
  11.  
  12. @RequestMapping(value = "/")
  13. public String index(){
  14. return createBean().toString();
  15. }
  16. }

六、AOP注解

实现AOP功能使用AspectJ注解
1、需要在pom.xml加入依赖:

  1. <dependency>
  2. <groupId>org.aspectj</groupId>
  3. <artifactId>aspectjweaver</artifactId>
  4. </dependency>

2、新建一个业务类 TestServiceImpl.java

  1. package com.example.demo;
  2.  
  3. import org.springframework.stereotype.Component;
  4.  
  5. @Component
  6. public class TestServiceImpl {
  7. public void testService(){
  8. System.out.println("要代理的业务方法");
  9. }
  10. }

3、新建一个代理类 ProxyService.java

  1. package com.example.demo;
  2.  
  3. import org.aspectj.lang.annotation.After;
  4. import org.aspectj.lang.annotation.Aspect;
  5. import org.aspectj.lang.annotation.Before;
  6. import org.springframework.stereotype.Component;
  7.  
  8. @Aspect
  9. @Component
  10. public class ProxyService {
  11. @Before("execution(* com.example.demo.*ServiceImpl.*(..))")
  12. public void before(){
  13. System.out.println("业务方法调用前执行");
  14. }
  15. @After("execution(* com.example.demo.*ServiceImpl.*(..))")
  16. public void after(){
  17. System.out.println("业务方法调用后执行");
  18. }
  19. }

4、修改启动类方法 DemoApplication.java

  1. package com.example.demo;
  2.  
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.boot.builder.SpringApplicationBuilder;
  6.  
  7. @SpringBootApplication
  8. public abstract class DemoApplication {
  9. public static void main(String[] args) {
  10. //SpringApplication.run(DemoApplication.class, args);
  11. new SpringApplicationBuilder(DemoApplication.class).properties(
  12. "spring.aop.proxy-target-class=true"
  13. ).run(args);
  14. }
  15. }

5、控制器 DemoController.java

  1. package com.example.demo;
  2.  
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6.  
  7. @RestController
  8. public class DemoController {
  9.  
  10. @Autowired
  11. TestServiceImpl testService;
  12.  
  13. @RequestMapping(value = "/")
  14. public String index(){
  15. testService.testService();
  16. System.out.println("TestServiceImpl的class:" + testService.getClass());
  17. return "";
  18. }
  19. }

浏览器访问:http://localhost:8080/,控制台中输出:
业务方法调用前执行
要代理的业务方法
业务方法调用后执行
TestServiceImpl的class:class com.example.demo.TestServiceImpl$$EnhancerBySpringCGLIB$$2a53cdeb

七、ComponentScan注解

ComponentScan注解主要用于检测使用@Component修饰的组件,包括间接使用@Component的组件(如@Service、@Repository、@Controller

),并把它们注册到Spring容器中。

Spring的常用注解的更多相关文章

  1. Spring Boot常用注解总结

    Spring Boot常用注解总结 @RestController和@RequestMapping注解 @RestController注解,它继承自@Controller注解.4.0之前的版本,Spr ...

  2. Spring MVC学习总结(2)——Spring MVC常用注解说明

        使用Spring MVC的注解及其用法和其它相关知识来实现控制器功能. 02     之前在使用Struts2实现MVC的注解时,是借助struts2-convention这个插件,如今我们使 ...

  3. Spring学习总结(2)——Spring的常用注解

    本文汇总了Spring的常用注解,以方便大家查询和使用,具体如下: 使用注解之前要开启自动扫描功能 其中base-package为需要扫描的包(含子包). ? 1 <context:compon ...

  4. Spring Boot 常用注解汇总

    一.启动注解 @SpringBootApplication @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documen ...

  5. 接近8000字的Spring/SpringBoot常用注解总结!安排!

    0.前言 大家好,我是 Guide 哥!这是我的 221 篇优质原创文章.如需转载,请在文首注明地址,蟹蟹! 本文已经收录进我的 75K Star 的 Java 开源项目 JavaGuide:http ...

  6. Spring/SpringBoot常用注解总结

    转自:[Guide哥] 0.前言 可以毫不夸张地说,这篇文章介绍的 Spring/SpringBoot 常用注解基本已经涵盖你工作中遇到的大部分常用的场景.对于每一个注解我都说了具体用法,掌握搞懂,使 ...

  7. Spring MVC常用注解

    cp by http://www.cnblogs.com/leskang/p/5445698.html 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由Di ...

  8. Spring Ioc 常用注解

    在开发中spring ioc的配置方式有多种方式,常用的一般都是byName.byType .以及其自动装配可以查看http://www.cnblogs.com/gubai/p/9140840.htm ...

  9. spring 、spring boot 常用注解

    @Profile 1.用户配置文件注解. 2.使用范围: @Configration 和 @Component 注解的类及其方法, 其中包括继承了 @Component 的注解: @Service. ...

  10. Spring 中常用注解原理剖析

    前言 Spring 框架核心组件之一是 IOC,IOC 则管理 Bean 的创建和 Bean 之间的依赖注入,对于 Bean 的创建可以通过在 XML 里面使用 <bean/> 标签来配置 ...

随机推荐

  1. JavaWeb中实现通过邮箱找回密码

    在开发JavaWeb项目中,利用邮箱帮用户找回密码.效果展示:   需要一个发送邮件的jar包 : javax.mail .jar1.JSP页面(设置邮箱输入框) HTML: <p >请输 ...

  2. Java连载61-异常的机制与分类

    一.is a.is like a.has a 1.is a(就是继承) public class Animal{ public void method1{ } } public class Dog e ...

  3. 基于MbedTLS的AES加密实现,含STM32H7和STM32F4的实现例程

    说明: 1.mbedTLS的前身是PolarSSL,开源免费. 主要提供了的SSL/TLS支持(在传输层对网络进行加密),各种加密算法,各种哈希算法,随机数生成以及X.509(密码学里公钥证书的格式标 ...

  4. 【zabbix告警监控】配置zabbix监控nginx服务

    zabbix监控nginx,nginx需要添加--with-http_stub_status模块 使用zabbix监控nginx,首先nginx需要配置开启ngx_status.但是我这边nginx安 ...

  5. Java基础语法02-流程控制-if-switch-for-while

    流程控制语句 顺序结构 任何编程语言中最常见的程序结构就是顺序结构.顺序结构就是程序从上到下逐行地执行,中间没有任何判断和跳转. 分支结构 if(条件表达式){ 语句体;} 执行流程 首先判断条件表达 ...

  6. Java 添加超链接到Word文档

    对特定元素添加超链接后,用户可以通过点击被链接的元素来激活这些链接,通常在被链接的元素下带有下划线或者以不同的颜色显示来进行区分.按照使用对象的不同,链接可以分为文本超链接,图像超链接,E-mail链 ...

  7. HeadFirst设计模式<1>

    HeadFirst设计模式<1> 1 策略模式 鸭子飞行和嘎嘎叫策略 2 工厂模式 简单工厂 工厂方法 抽象工厂 简单工厂简单的pizza工厂 通过一个工厂类的方法,创建和返回对象实例 原 ...

  8. Redis 到底是怎么实现“附近的人”这个功能的呢?

    作者简介 万汨,饿了么资深开发工程师.iOS,Go,Java均有涉猎.目前主攻大数据开发.喜欢骑行.爬山. 前言:针对“附近的人”这一位置服务领域的应用场景,常见的可使用PG.MySQL和MongoD ...

  9. [转]RPA Developer Advanced Certification - Exam #1 UiPath 练习

    本文转自:https://github.com/miyaichi/CertificationExam1 RPA Developer Advanced Certification - Exam #1 E ...

  10. Git问题汇总

    1.fatal: refusing to merge unrelated histories $git pull origin master --allow-unrelated-histories 2 ...