Spring注解开发详细教程(三)

简介: Spring注解开发详细教程

7.4BeanPostProcessor—bean的后置处理器


在bean初始化前后进行一些处理工作;


postProcessBeforeInitialization:在初始化之前工作


postProcessAfterInitialization:在初始化之后工作


创建MyBeanPostProcessor,实现BeanPostProcessor接口


/**
 * 后置处理器:初始化前后进行处理工作
 * 将后置处理器加入到容器中
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor{
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization"+beanName+"=>"+bean);
        return bean;
    }
}

运行结果:

2a3f9c7d215e45349c62f41d9f541594.png

BeanPostProcessor原理

populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
initializeBean
{
   applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
   applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

Spring底层对 BeanPostProcessor 的使用;

bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;

8.@Value

作用:为属性赋值

基本数值

可以写SpEL:#{}

可以写${};取出配置文件[properties]中的值(在运行环境变量中的值)

Person类

public class Person {
    //使用@Value赋值
    //1.基本数值
    //2.可以写SpEL:#{}
    //3.可以写${};取出配置文件[properties]中的值(在运行环境变量中的值)
    @Value("zhangsan")
    private String name;
    @Value("#{20+1}")
    private Integer age;
    @Value("${person.nickName}")
    private String nickName;
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", nickName='" + nickName + '\'' +
                '}';
    }
    public Person(){
    }
}

MainConfig配置类:

//使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;加载完外部的配置文件以后使用${}取出配置文件的值
@PropertySource(value = {"classpath:person.properties"})
//@PropertySources(value = {@PropertySource({}),@PropertySource({})})
@Configuration
public class MainConfigOfPropertyValues {
    @Bean
    public Person person(){
        return new Person();
    }
}

测试

@Test
public void test08(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
    Person person = (Person) applicationContext.getBean("person");
    System.out.println(person);
    Environment environment = applicationContext.getEnvironment();
    String value = environment.getProperty("person.nickName");//通过environment也可以获取配置文件的属性值.
    System.out.println(value);
    applicationContext.close();
}

person.properties文件

person.nickName=\u5C0F\u674E\u56DB


运行结果:

3604c6fbcfaa414eacb4bbcea7b9f420.png

9.自动装配

Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;

9.1@Autowired:自动注入

1)、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值


2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找 applicationContext.getBean(“bookDao”)

@Controller
public class BookController {
    @Autowired
    private BookService bookService;
}
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;
    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}
// 默认是类名首字母小写
@Repository
public class BookDao {
    private String Label = "1";
    public String getLabel() {
        return Label;
    }
    public void setLabel(String label) {
        Label = label;
    }
    @Override
    public String toString() {
        return "BookDao{" +
                "Label='" + Label + '\'' +
                '}';
    }
}
@Configuration
@ComponentScan({"com.rg.service","com.rg.dao","com.rg.controller"})
public class MainConfigOfAutowired {
    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLabel("2");
        return bookDao;
    }
}

测试:

@Test
 public void test01(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
    //获取BookService中注入的BookDao
    BookService bookService = applicationContext.getBean(BookService.class);
    //BookDao bean = applicationContext.getBean(BookDao.class);  当IOC容器中有多个对象时不能用类.class进行获取对象.
    //System.out.println(bean);
    System.out.println(bookService);
}

运行结果:

IOC容器中有bookDao和bookDao2,因为@Autowired 下面的需要的名字为bookDao,所以里面注册的就是bookDao对象.如果改为bookDao2则里面注册的就是bookDao2对象.

3cea2e49a8154848bdac8418560b8745.png

3)、使用@Qualifier指定需要装配的组件的id,而不是默认使用属性名

BookService{
    @Qualifier("bookDao2")  
      @Autowired
      BookDao  bookDao;
}


这样bookDao里面注册的就是bookDao2.

4)、自动装配默认一定要将属性赋值好,没有就会报错;通过使用@Autowired(required=false); 可以当有的时候进行注册,没有的时候为null.

BookService{
    @Qualifier("bookDao2")  
      @Autowired(required = false)
      BookDao  bookDao;
}

e2645484742347898fc59ede657394fb.png

5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;也可以继续使用@Qualifier指定需要装配的bean的名字

BookService{
    //@Qualifier("bookDao2")  
      @Autowired(required = false)
      BookDao  bookDao;
}
@Repository
public class BookDao {
    ......
}
@Configuration
@ComponentScan({"com.rg.service","com.rg.dao","com.rg.controller"})
public class MainConfigOfAutowired {
    @Primary
    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLabel("2");
        return bookDao;
    }
}

当没有Qualifier时, 为BookDao加上@Primary,则其优先权会升高,会优先注册该对象. 但如果此时有Qualifier,则由里面的名称决定.

481b56bf89814d7885d44a5e51bf8710.png

6 )、扩展:Spring还支持使用@Resource(JSR250)和@Inject(JSR330) [java规范的注解]

@Resource:

可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
没有能支持@Primary功能没有支持@Autowired(reqiured=false);

@Inject:

需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;支持@Primary

@Autowired:Spring定义的规范; @Resource、@Inject都是java规范


小结:


@Autowired 当IOC容器中只有一个时,可以这样使用.此时由 待注册的名称决定.


@Autowired经常和@Qualifier一起使用;此时,可以打破默认,由Qualifier指定的对象注册.


@Autowired还可以和@Primary+其他组件注解(@Bean,@Service,@Controller…),从而提升其优先级,优先被使用.


9.2 扩展:@Autowired使用的位置:

@Autowired:构造器,参数,方法,属性;都是从容器中获取参数组件的值

1.放在参数位置

1)、放在属性位置或setter方法上

默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作


@Component
public class Car {
  ....
}
@Component
public class Boss {
    //@Autowired:属性位置.
    private Car car;
    public Car getCar() {
        return car;
    }
    //标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值
    //方法使用的参数,自定义类型从IOC容器中获取.
    @Autowired//方法上
    public void setCar(Car car) {
        this.car = car;
    }
}

2 ) 、[标在构造器上]:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取

@Component
public class Car {
  ....
}
@Component
public class Boss {
    private Car car;
    @Autowired//可省略
    public Boss(Car car){
        this.car = car;
        System.out.println("Boss 有参构造器...");
    }
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    @Override
    public String toString() {
        return "Boss{" +
                "car=" + car +
                '}';
    }
}

程序中:会自动调用有参构造为Boss中的Car进行赋值.IOC容器中的Car和Boss中的Car是同一个.

3)、[标注在方法位置]:@Bean+方法参数;参数从容器中获取;默认不写@Autowired效果是一样的;都能自动装配

@Bean
@Autowired
public Color color(Car car){
    Color color = new Color();
    color.setCar(car);
    return color;
}

注:参数卸载方法上或者 参数之前,或者省略都是可以的.

9.3@Profile

Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;


如:当开发环境时我们自动在环境中加入开发的相关组件,当是测试环境时,自动添加测试的相关组件,当是生成环境时,自动添加生产的组件.


@Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件


@Configuration
@PropertySource("classpath:/jdbc.properties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware {
    private String driverClass;
    @Value("${jdbc.user}") // @value放在属性上
    private String user;
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        //this.resolver = resolver;
        driverClass = resolver.resolveStringValue("${jdbc.driver}");
    }
    @Bean
    public Yellow yellow(){
        return new Yellow();
    }
    @Bean("prodDataSource")
    @Profile("prod")
    //@Profile("default")  @Value放在参数上
    public DataSource dataSourceProd(@Value("${jdbc.password}")String pwd) throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql:///goods");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }
    @Profile("test")
    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${jdbc.password}")String pwd) throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql:///test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }
    @Bean("devDataSource")
    @Profile("dev")
    public DataSource dataSourceDev(@Value("${jdbc.password}")String pwd) throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql:///travel");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }
}

补充:


使用配置文件的两种方式:


使用@PropertySource(“classpath:/文件名称”),搭配@Value(“键”)

类实现EmbeddedValueResolverAware通过 resolver.resolveStringValue 获取键对应的值.

测试:

   @Test
    public void test01(){
        //1.使用命令行动态参数,在Edit Configurations的VM options中加入 -Dspring.profiles.active=test
        //2.使用代码的方式激活某种环境
        //1.创建一个applicationContext
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //2.设置需要激活的环境
        //AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
       applicationContext.getEnvironment().setActiveProfiles("dev","test");
       //3.注册主配置类
       applicationContext.register(MainConfigOfProfile.class);
       //4.启动刷新容器
        applicationContext.refresh();
        String[] names = applicationContext.getBeanNamesForType(DataSource.class);
        System.out.println(names);
        for (String name : names) {
            System.out.println(name);
        }
        applicationContext.close();
    }

运行结果:

43cf405187494703ad5fffe8055b35cb.png

2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效

如在类上加@Profile(“test”),使用的是开发环境,则里面的所有配置都无效.只有一致时才生效.

3)、没有标注环境标识的bean在,任何环境下都是加载的;


根据尚硅谷 雷神的<<Spring注解开发>> 整理总结

相关文章
|
5月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
5月前
|
前端开发 Java UED
从基础到进阶:Spring Boot + Thymeleaf 整合开发中的常见坑与界面优化
本文深入探讨了 **Spring Boot + Thymeleaf** 开发中常见的参数绑定问题与界面优化技巧。从基础的 Spring MVC 请求参数绑定机制出发,分析了 `MissingServletRequestParameterException` 的成因及解决方法,例如确保前后端参数名、类型一致,正确设置请求方式(GET/POST)。同时,通过实际案例展示了如何优化支付页面的视觉效果,借助简单的 CSS 样式提升用户体验。最后,提供了官方文档等学习资源,帮助开发者更高效地掌握相关技能。无论是初学者还是进阶用户,都能从中受益,轻松应对项目开发中的挑战。
175 0
|
3月前
|
Java 测试技术 数据库
说一说 SpringBoot 整合 Junit5 常用注解
我是小假 期待与你的下一次相遇 ~
|
3月前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
311 0
|
5月前
|
人工智能 Java 定位技术
Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合
本文详细讲解了Java开发者如何基于Spring AI Alibaba框架玩转MCP(Model Context Protocol),涵盖基础概念、快速体验、服务发布与调用等内容。重点包括将Spring应用发布为MCP Server(支持stdio与SSE模式)、开发MCP Client调用服务,以及在Spring AI Alibaba的OpenManus中使用MCP增强工具能力。通过实际示例,如天气查询与百度地图路线规划,展示了MCP在AI应用中的强大作用。最后总结了MCP对AI开发的意义及其在Spring AI中的实现价值。
1376 9
|
5月前
|
人工智能 缓存 自然语言处理
保姆级Spring AI 注解式开发教程,你肯定想不到还能这么玩!
这是一份详尽的 Spring AI 注解式开发教程,涵盖从环境配置到高级功能的全流程。Spring AI 是 Spring 框架中的一个模块,支持 NLP、CV 等 AI 任务。通过注解(如自定义 `@AiPrompt`)与 AOP 切面技术,简化了 AI 服务集成,实现业务逻辑与 AI 基础设施解耦。教程包含创建项目、配置文件、流式响应处理、缓存优化及多任务并行执行等内容,助你快速构建高效、可维护的 AI 应用。
|
2月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
665 0
|
6月前
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
263 0