spring学习笔记(六)自定义spring-boot-starter(2)

简介: 上篇文章我们主要讲了spring自动装配的原理,我们知道了springboot在启动的时候会自动去读.factories文件,在factories文件中,autoConfiguration对应的就是我们程序启动时自己预加载的类,另外我也提到了另外一个比较核心的注解,即@ConditionOnxxx。详情点击https://blog.csdn.net/qq_41907991/article/details/88704448。

这篇文章我们主要分析下@ConditionOnxxx注解,以及自己实现一个starter。下面开始分析我们的@ConditionOnxxx注解。先看代码:

我们以@ConditionalOnMissingBean这个注解来分析原理:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {....}

很明显,上面的核心注解就是@Conditional注解,我们接下来分析这个注解,直接上代码看效果

package com.study.spring.condition.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 23:16 2019/3/25
 */
public class CatCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("what").equals("cat");
    }
}
package com.study.spring.condition.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 23:16 2019/3/25
 */
public class DogCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("what").equals("dog");
    }
}

上面这两个类,是我自定义的两个条件

package com.study.spring.condition.model;
import com.study.spring.condition.condition.CatCondition;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 23:19 2019/3/25
 */
@Component
@Conditional({CatCondition.class})
public class Cat {
    public Cat(){
        System.out.println("猫来了,喵喵喵~~");
    }
}
package com.study.spring.condition.model;
import com.study.spring.condition.condition.DogCondition;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 23:18 2019/3/25
 */
@Component
@Conditional({DogCondition.class})
public class Dog {
    public Dog(){
        System.out.println("dog 来了,汪汪汪~~~");
    }
}

主要是为了通过条件控制我们这两个类的加载

what:cat

这是配置文件中的内容

package com.study.spring.condition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConditionApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConditionApplication.class, args);
    }
}

这是启动类

启动程序,可以看到程序打印:

经过上面的程序我相信大家对这个@conditional注解已经有了一定的了解

接下来我们来实现我们的自定义starter

pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.study.spring</groupId>
    <artifactId>starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>myAutoconfig-spring-boot-starter</name>
    <description>Demo project for Spring Boot</description>
    <packaging>jar</packaging>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <!--为了生成spring-configuration-metadata.json-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

整体项目结构如下

image.png

package com.study.spring.starter.AutoConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * @author dmz
 * @date Create in 22:06 2019/3/23
 */
@Data
@ConfigurationProperties(prefix = "config")
public class Config {
    private String name;
    private Integer age;
}
package com.study.spring.starter.AutoConfig;
import com.study.spring.starter.service.MyService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author dmz
 * @date Create in 21:24 2019/3/23
 */
@Configuration
@EnableConfigurationProperties(Config.class)
@ConditionalOnClass(MyService.class)
public class MyAutoConfig {
    @Bean
    @ConditionalOnMissingBean(MyService.class)
    public MyService getMyService() {
        return new MyService();
    }
}
package com.study.spring.starter.service;
import com.study.spring.starter.AutoConfig.Config;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * @author dmz
 * @date Create in 21:53 2019/3/23
 */
public class MyService {
    @Autowired
    private Config config;
    public void say() {
        System.out.println("自定义的starter来了,say:" + config.getName());
    }
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 *保留启动类,主要是为了执行maven的命令,
 * 打包到我们的本地仓库
 */
@SpringBootApplication
public class StarterApplication{
    public static void main(String[] args) {
        SpringApplication.run(StarterApplication.class, args);
    }
}

spring.factories文件如下

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.study.spring.starter.AutoConfig.MyAutoConfig

测试代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.study.spring</groupId>
    <artifactId>starter-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>starter-test</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
         <!--引入我们的依赖-->
        <dependency>
            <groupId>com.study.spring</groupId>
            <artifactId>starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

启动类:

package com.study.spring.startertest;
import com.study.spring.starter.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StarterTestApplication implements ApplicationRunner {
    @Autowired
    private MyService myService;
    public static void main(String[] args) {
        SpringApplication.run(StarterTestApplication.class, args);
    }
    @Override
    public void run(ApplicationArguments args) throws Exception {
        myService.say();
    }
}

我们在测试项目中加了配置信息

image.png

运行结果如下:

  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)
2019-03-27 00:09:52.995  INFO 19468 --- [           main] c.s.s.s.StarterTestApplication           : Starting StarterTestApplication on DESKTOP-N88SU6M with PID 19468 (C:\Users\dell\Desktop\spring-master\starter-test\target\classes started by dell in C:\Users\dell\Desktop\spring-master)
2019-03-27 00:09:52.999  INFO 19468 --- [           main] c.s.s.s.StarterTestApplication           : No active profile set, falling back to default profiles: default
2019-03-27 00:09:53.416  INFO 19468 --- [           main] c.s.s.s.StarterTestApplication           : Started StarterTestApplication in 0.722 seconds (JVM running for 1.243)
自定义的starter来了,say:zhangsan
Process finished with exit code 0

验证成功

项目github地址https://github.com/daimingzhi/spring.git

相关文章
|
9天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
35 9
|
29天前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
34 9
|
30天前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
19 1
|
1月前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
56 2
|
1月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
84 1
|
1月前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
25 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
1月前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
23 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
1月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
64 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
1月前
|
Java 关系型数据库 MySQL
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
这篇文章是关于如何使用Spring Boot框架通过JdbcTemplate操作MySQL数据库的教程。
24 0
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
|
1月前
|
Java 测试技术 Spring
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
这篇文章介绍了Spring Boot中配置文件的语法、如何读取配置文件以及如何通过静态工具类读取配置文件。
46 0
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件