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

package com.example.demo;

public class MyBean {

    public MyBean(String id){
this.id = id;
} private String id; public String getId() {
return id;
} public void setId(String id) {
this.id = id;
}
}

2、新建类 MyConfig.java

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class MyConfig { //默认bean的名称为方法名,即下面的getMyBean
@Bean
public MyBean getMyBean(){
return new MyBean("1");
} //设置bean的名称为bean
@Bean("bean2")
public MyBean getMyBean2(){
return new MyBean("2");
}
}

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

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @SpringBootApplication
@RestController
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} @Autowired
ApplicationContext ctx; @RequestMapping(value = "/")
public String index(){
//根据类型获取bean的名称
String[] names = ctx.getBeanNamesForType(MyBean.class);
for(String name : names){
System.out.println(name);
} //获取bean
MyBean bean1 = (MyBean)ctx.getBean("getMyBean");
System.out.println(bean1.getId()); MyBean bean2 = (MyBean)ctx.getBean("bean2");
System.out.println(bean2.getId()); return "";
}
}

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

项目结构

二、依赖注入

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

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

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

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @SpringBootApplication
@RestController
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} //使用@Resource注入
@Resource(name="getMyBean")
MyBean myBean1; //使用@Autowired注入
@Autowired
MyBean bean2; @RequestMapping(value = "/")
public String index(){
System.out.println(myBean1.getId());
System.out.println(bean2.getId());
return "";
}
}

浏览器访问: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控制台会报异常信息:

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

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

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @SpringBootApplication
@RestController
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} MyBean bean2; //构造注入
@Autowired
public DemoApplication(MyBean bean2){
this.bean2 = bean2;
} @RequestMapping(value = "/")
public String index(){
System.out.println(bean2.getId());
return "";
}
}

三、使用Primary注解

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

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

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; @Configuration
public class MyConfig { //默认bean的名称为方法名,即下面的getMyBean
@Bean
@Primary
public MyBean getMyBean(){
return new MyBean("1");
} //设置bean的名称为bean
@Bean("bean2")
public MyBean getMyBean2(){
return new MyBean("2");
}
}

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

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @SpringBootApplication
@RestController
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} //使用@Resource注入
@Resource(name="getMyBean")
MyBean myBean1; //使用@Autowired注入
@Autowired
MyBean bean2; @RequestMapping(value = "/")
public String index(){
System.out.println(myBean1.getId());
System.out.println(bean2.getId());
return "";
}
}

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

四、Scope注解

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

1、修改代码 MyConfig.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @SpringBootApplication
@RestController
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} @Autowired
ApplicationContext ctx; @RequestMapping(value = "/")
public String index(){
String s = "prototype:" + ctx.getBean("bean1") + "<br /> "
+ "singleton:" + ctx.getBean("bean2") + "<br /> ";
return s;
}
}

浏览器访问: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,如下所示:

    //注入一个非单态的bean
@Autowired
private MyBean bean1; @RequestMapping(value = "/")
public String index(){
return bean1.toString();
}

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

五、方法注入

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

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class DemoController { @Autowired
private ApplicationContext ctx; private MyBean getBean1(){
return (MyBean)ctx.getBean("bean1");//一个非单态的bean
} @RequestMapping(value = "/")
public String index(){
return getBean1().toString();
}
}

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

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

package com.example.demo;

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public abstract class DemoController {
@Lookup("bean1")
public abstract MyBean createBean() ; @RequestMapping(value = "/")
public String index(){
return createBean().toString();
}
}

六、AOP注解

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

        <dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>

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

package com.example.demo;

import org.springframework.stereotype.Component;

@Component
public class TestServiceImpl {
public void testService(){
System.out.println("要代理的业务方法");
}
}

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

package com.example.demo;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; @Aspect
@Component
public class ProxyService {
@Before("execution(* com.example.demo.*ServiceImpl.*(..))")
public void before(){
System.out.println("业务方法调用前执行");
}
@After("execution(* com.example.demo.*ServiceImpl.*(..))")
public void after(){
System.out.println("业务方法调用后执行");
}
}

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

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder; @SpringBootApplication
public abstract class DemoApplication {
public static void main(String[] args) {
//SpringApplication.run(DemoApplication.class, args);
new SpringApplicationBuilder(DemoApplication.class).properties(
"spring.aop.proxy-target-class=true"
).run(args);
}
}

5、控制器 DemoController.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class DemoController { @Autowired
TestServiceImpl testService; @RequestMapping(value = "/")
public String index(){
testService.testService();
System.out.println("TestServiceImpl的class:" + testService.getClass());
return "";
}
}

浏览器访问: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. 1.Android-入门之系统架构介绍

    1.Android 系统架构 android分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核心层,如下图所示: 2.application应用程序层 该层提供一些核 ...

  2. python基础之列表讲解

    列表是最常用的Python数据类型,它可以作为一个方括号内的逗号分隔值出现. 列表的数据项不需要具有相同的类型 如下图所示,创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可.(接下来的演 ...

  3. 2019年Java面试题基础系列228道(2)

    21.描述一下 JVM 加载 class 文件的原理机制? JVM 中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java 中的类加载器是一个重要的 Java 运行时系统组件,它 ...

  4. ELK 安装部署小计

    ELK的安装部署已经是第N次了! 其实也很简单,这里记下来,以免忘记. #elasticsearch安装部署 wget https://artifacts.elastic.co/downloads/e ...

  5. 分布式图数据库 Nebula RC2 发布:增强了 CSV Importer 功能

    Nebula Graph 是开源的分布式图数据库,可应用于知识图谱.社交推荐.风控.IoT 等场景. 本次 RC2 主要新增 GO FROM ... REVERSELY 和 GROUP BY 等语句, ...

  6. 从零开始ant-design-vue-pro开发笔记(一)

    开始 从这里开始是用ant-design-vue组件写ant-design-vue-pro这个后台项目实现步骤的从零开始搭建的过程,视频地址,它采用了ant-desgin-vue的组件库作为素材开发, ...

  7. Jenkins使用SSH构建Go项目并执行

    目录 下载插件 配置要部署的服务器 构建项目 Jenkinx可以帮助我们通过SSH插件,将项目直接部署到指定的服务器. 下载插件 (1)点击左侧的"系统管理"菜单 ,然后点击 (2 ...

  8. 更换国内pip

    pip国内的一些镜像 原始地址:https://pypi.python.org/simple 国内地址: 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技 ...

  9. DispatchProxy实现动态代理及AOP

    DispatchProxy类是DotnetCore下的动态代理的类,源码地址:Github,官方文档:MSDN.主要是Activator以及AssemblyBuilder来实现的(请看源码分析),园子 ...

  10. Access the Security System in Code 在代码中访问安全系统

    This lesson will guide you through using the static SecuritySystem class to check whether or not a u ...