Spring的常用注解

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:[email protected]
singleton:[email protected]
prototype:[email protected]
......

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

    //注入一个非单态的bean
    @Autowired
    private MyBean bean1;

    @RequestMapping(value = "/")
    public String index(){
        return bean1.toString();
    }

浏览器访问:http://localhost:8080/,多次刷新,页面都是显示如下:
[email protected]
说明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/,多次刷新,页面每次都变化:
[email protected]
[email protected]
......

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容器中。

原文地址:https://www.cnblogs.com/gdjlc/p/11600975.html

时间: 2024-10-30 04:55:32

Spring的常用注解的相关文章

Spring MVC常用注解

cp by http://www.cnblogs.com/leskang/p/5445698.html 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示.在SpringMVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Control

spring mvc 常用注解标签详解

1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示.在SpringMVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestP

Spring中常用注解的介绍

spring中使用注解时配置文件的写法: <?xml version="1.0" encoding="UTF-8"?> <span style="font-size:18px;"><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-in

spring较为常用注解

@Configuration 从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器. @enableAsync注解的意思是可以异步执行,就是开启多线程的意思.可以标注在方法.类上 spring线

spring mvc常用注解的说明

最近一段时间学习了springboot,所以熟悉一下mvc中常用的注解,这样可以方便开发 简介: @RequestMapping RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上.用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径. RequestMapping注解有六个属性,下面我们把她分成三类进行说明. 1. value, method: value:     指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明): met

spring boot常用注解使用小结

1.@RestController和@RequestMapping注解 4.0重要的一个新的改进是@RestController注解,它继承自@Controller注解. 4.0之前的版本,Spring MVC的组件都使用@Controller来标识当前类是一个控制器servlet.使用这个特性,我们可以开发REST服务的时候不需要使用@Controller,而专门的@RestController. 当你实现一个RESTful web services的时候,response将一直通过respo

spring mvc常用注解总结

1.@RequestMapping@RequestMappingRequestMapping是一个用来处理请求地址映射的注解(将请求映射到对应的控制器方法中),可用于类或方法上.用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径.RequestMapping请求路径映射,如果标注在某个controller的类级别上,则表明访问此类路径下的方法都要加上其配置的路径:最常用是标注在方法上,表明哪个具体的方法来接受处理某次请求. @Controller @RequestMapping(val

spring一些常用注解及其作用

@Controller 处理http请求的控制器例子: @Controller public class HelloController { @RequestMapping(value="/hello",method= RequestMethod.GET) public String sayHello(){ return "hello"; } } @RestController Spring4之后新加入的注解,原来返回json需要@ResponseBody和@Con

Spring-04.Spring的常用注解

认知: 学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样 的,都是要降低程序间的耦合.只是配置的形式不一样. 1 常用IOC注解按照作用分类 曾经XML的配置: <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" scope="" init-method="" d

阶段3 2.Spring_04.Spring的常用注解_5 自动按照类型注入

运行出现了空指针异常 @Autowired 注解出现的位置 AutoWired的代码 常用的就是写类上和方法上. 运行测试,刚才运行是一个空指针异常 也就是通过Autowired 这个accountDao这个对象不为空了. 注入成功原理 自动按照类型注入.IAccountDao去Spring的容器里面直接找的Value值 如果把实现类继承接口IAccountDao这里代码注释掉的话 再次运行就发现注不进去报错. 假设容器中两个实现类 复制一份改个名字 id后面也加上2 第一个实现的实现接口的代码