在之前的文章中,我们分析过SpringBoot内部的自动化配置原理和自动化配置注解开关原理。
我们先简单分析一下mybatis starter的编写,然后再编写自定义的starter。
mybatis中的autoconfigure模块中使用了一个叫做MybatisAutoConfiguration的自动化配置类。
这个MybatisAutoConfiguration需要在这些Condition条件下才会执行:
- @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })。需要SqlSessionFactory和SqlSessionFactoryBean在classpath中都存在
- @ConditionalOnBean(DataSource.class)。 spring factory中需要存在一个DataSource的bean
- @AutoConfigureAfter(DataSourceAutoConfiguration.class)。需要在DataSourceAutoConfiguration自动化配置之后进行配置,因为mybatis需要数据源的支持
同时在META-INF目录下有个spring.factories这个properties文件,而且它的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration,这样才会被springboot加载:
1
2
3
|
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration |
有了这些东西之后,mybatis相关的配置会被自动加入到spring container中,只要在maven中加入starter即可:
1
2
3
4
5
|
< dependency >
< groupId >org.mybatis.spring.boot</ groupId >
< artifactId >mybatis-spring-boot-starter</ artifactId >
< version >1.1.1</ version >
</ dependency >
|
编写自定义的starter
接下来,我们来编写自定义的starter:log-starter。
这个starter内部定义了一个注解,使用这个注解修饰方法之后,该方法的调用会在日志中被打印并且还会打印出方法的耗时。starter支持exclude配置,在exclude中出现的方法不会进行计算。
pom文件:
1
2
3
4
5
6
7
8
9
10
11
12
|
< parent >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starters</ artifactId >
< version >1.3.5.RELEASE</ version >
</ parent >
< dependencies >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter</ artifactId >
</ dependency >
</ dependencies >
|
定义修饰方法的注解@Log:
1
2
3
4
5
6
7
8
9
10
|
package me.format.springboot.log.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.METHOD)
public @interface Log { }
|
然后是配置类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package me.format.springboot.log.autoconfigure;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
@ConfigurationProperties (prefix = "mylog" )
public class LogProperties {
private String exclude;
private String[] excludeArr;
@PostConstruct
public void init() {
this .excludeArr = StringUtils.split(exclude, "," );
}
public String getExclude() {
return exclude;
}
public void setExclude(String exclude) {
this .exclude = exclude;
}
public String[] getExcludeArr() {
return excludeArr;
}
} |
接下来是AutoConfiguration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package me.format.springboot.log.autoconfigure;
import me.format.springboot.log.annotation.Log;
import me.format.springboot.log.aop.LogMethodInterceptor;
import org.aopalliance.aop.Advice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration @EnableConfigurationProperties (LogProperties. class )
public class LogAutoConfiguration extends AbstractPointcutAdvisor {
private Logger logger = LoggerFactory.getLogger(LogAutoConfiguration. class );
private Pointcut pointcut;
private Advice advice;
@Autowired
private LogProperties logProperties;
@PostConstruct
public void init() {
logger.info( "init LogAutoConfiguration start" );
this .pointcut = new AnnotationMatchingPointcut( null , Log. class );
this .advice = new LogMethodInterceptor(logProperties.getExcludeArr());
logger.info( "init LogAutoConfiguration end" );
}
@Override
public Pointcut getPointcut() {
return this .pointcut;
}
@Override
public Advice getAdvice() {
return this .advice;
}
} |
由于计算方法调用的时候需要使用aop相关的lib,所以我们的AutoConfiguration继承了AbstractPointcutAdvisor。这样就有了Pointcut和Advice。Pointcut是一个支持注解的修饰方法的Pointcut,Advice则自己实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package me.format.springboot.log.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
public class LogMethodInterceptor implements MethodInterceptor {
private Logger logger = LoggerFactory.getLogger(LogMethodInterceptor. class );
private List<String> exclude;
public LogMethodInterceptor(String[] exclude) {
this .exclude = Arrays.asList(exclude);
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String methodName = invocation.getMethod().getName();
if (exclude.contains(methodName)) {
return invocation.proceed();
}
long start = System.currentTimeMillis();
Object result = invocation.proceed();
long end = System.currentTimeMillis();
logger.info( "====method({}), cost({}) " , methodName, (end - start));
return result;
}
} |
最后resources/META-INF/spring.factories中加入这个AutoConfiguration:
1
2
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ me.format.springboot.log.autoconfigure.LogAutoConfiguration |
我们在项目中使用这个log-starter:
1
2
3
4
5
|
< dependency >
< groupId >me.format.springboot</ groupId >
< artifactId >log-starter</ artifactId >
< version >1.0-SNAPSHOT</ version >
</ dependency >
|
使用配置:
1
|
mylog.exclude=core,log |
然后编写一个简单的Service:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Service public class SimpleService {
@Log
public void test( int num) {
System.out.println( "----test---- " + num);
}
@Log
public void core( int num) {
System.out.println( "----core---- " + num);
}
public void work( int num) {
System.out.println( "----work---- " + num);
}
} |
使用单元测试分别调用这3个方法,由于work方法没有加上@Log注解,core方法虽然加上了@Log注解,但是在配置中被exclude了,只有test方法可以正常计算耗时:
1
2
3
4
|
----test---- 666
2016 - 11 - 16 01 : 29 : 32.255 INFO 41010 --- [ main] m.f.s.log.aop.LogMethodInterceptor : ====method(test), cost( 36 )
----work---- 666
----core---- 666
|
总结:
自定义springboot的starter,注意这两点。
- 如果自动化配置类需要在程序启动的时候就加载,可以在META-INF/spring.factories文件中定义。如果本次加载还需要其他一些lib的话,可以使用ConditionalOnClass注解协助
- 如果自动化配置类要在使用自定义注解后才加载,可以使用自定义注解+@Import注解或@ImportSelector注解完成
参考:
相关推荐
我们可以参照 spring-boot-starter,我们发现其中没有代码,我们在看它的 pom 中的依赖中有个 springboot-starter: ```xml <groupId>org.springframework.boot <artifactId>spring-boot-starter ``` 我们再看看...
最后,自定义Starter的目的是为了提高代码的复用性和可维护性。当你有一个通用的功能或一组组件,希望在多个Spring Boot项目中使用时,创建一个Starter是一个明智的选择。通过遵循Spring Boot的设计原则和最佳实践,...
总结,本项目【study-springboot】是一个实践案例,展示了如何在Spring Boot项目中使用自定义Starter组件。这不仅简化了配置,提高了代码的可复用性,同时也使得项目的构建和维护变得更加高效。通过分析项目文件和...
现在,让我们按照以下步骤创建一个自定义Starter: 1. **初始化项目**:使用Spring Initializr或者通过Maven Archetype创建一个新的Spring Boot项目,选择适当的依赖(如Web、Data JPA等)。 2. **创建pom.xml**:...
这个压缩包文件 "SpringBoot启动配置原理_SpringBoot自定义starters.zip" 显然是关于理解 Spring Boot 启动配置以及如何自定义 Starters 的教程资料。 **Spring Boot 启动配置原理** Spring Boot 的核心之一是其...
MyBatisPlus会自动为实体类生成Mapper接口,但为了更灵活地编写SQL,我们通常还会自定义Mapper接口。例如,有一个`User`实体类,我们可以创建对应的`UserMapper`接口和`UserMapper.xml`文件。 在实体类中,我们需要...
SpringBoot自定义Starter的具体流程 SpringBoot自定义Starter是一种特殊的starter,它可以根据项目的需求进行自定义和配置,从而满足不同的业务需求。在 본节中,我们将详细介绍SpringBoot自定义Starter的具体流程...
通过创建自定义Starter,我们可以将常见的配置、依赖和初始化逻辑打包,使得在新项目中使用这些功能时,只需添加一个Maven或Gradle依赖即可。 在创建自定义Starter时,通常包括以下几个关键步骤: 1. **定义Maven...
为了验证自定义starter是否正常工作,需要编写测试用例。使用`@SpringBootTest`和`@Import`注解来加载自定义的starter,然后通过断言来确认预期的bean是否被正确地创建和配置。 8. **发布到Maven仓库** 将`my-...
3. **起步依赖(Starter POMs)**:SpringBoot通过一系列的起步依赖简化了Maven或Gradle的构建配置,如`spring-boot-starter-web`用于web应用,`spring-boot-starter-data-jpa`用于数据库访问。 4. **内嵌式容器**...
- **起步依赖**(Starter POMs):SpringBoot的Maven或Gradle模块提供了预配置的依赖集合,如`spring-boot-starter-web`用于Web开发。 - **内嵌服务器**:SpringBoot内建了Tomcat或Jetty等HTTP服务器,无需额外...
1. **起步依赖**:通过`spring-boot-starter`模块,可以轻松引入如Web、Data JPA、Actuator等关键功能。 2. **内嵌Web服务器**:如Tomcat或Jetty,无需额外配置即可启动HTTP服务。 3. **自动配置**:SpringBoot尝试...
2. **起步依赖**(Starters):SpringBoot的起步依赖是一种方便的Maven或Gradle配置,比如`spring-boot-starter-data-jpa`用于JPA数据访问,`spring-boot-starter-web`用于Web开发,它们帮助开发者快速添加所需依赖...
3. **提高开发效率**:由于SpringBoot内置了各种starter依赖,开发人员只需要引入所需的starter即可获得完整的功能,极大地提高了开发效率。 4. **简化部署**:SpringBoot支持打包成独立的JAR或WAR文件,这些文件...
此外,还需要编写一个Shiro配置类,继承自`WebSecurityConfigurerAdapter`,重写其方法来配置Shiro的FilterChainDefinitionSource,以及自定义的Realm。 认证流程主要包括以下步骤: 1. 用户提交用户名和密码。 2. ...
要创建自定义Starter,需编写`pom.xml`文件引入相关依赖,并创建自动配置类。 2. **命名规范**:自定义Starter的Maven模块名通常以`spring-boot-starter-`开头,如`spring-boot-starter-myapp`。 3. **`spring....
5. **运行时 Banner**:SpringBoot允许自定义启动时的Banner,展示项目信息。 6. **命令行界面(CLI)**:SpringBoot还提供了命令行工具,方便快速执行脚本和测试。 7. **YAML/Properties配置**:SpringBoot支持...
Spring Boot的自定义starter是开发人员扩展其功能和定制化应用的一种强大方式。本文将详细介绍创建自定义starter的完整步骤,以及如何利用starter模块来优化项目配置。 首先,理解starter的作用至关重要。starter是...
在SpringBoot中,`META-INF/spring.factories`文件可以用来声明自定义的配置初始化类。 9. **数据库集成**:SpringBoot与多种数据库兼容,如MySQL、Oracle等。使用`spring-boot-starter-data-jpa`可以快速集成JPA...
- **起步依赖(Starters)**:SpringBoot通过起步依赖来引入特定功能的库,例如Spring Web Starter,它包含Spring MVC和相关依赖,极大地简化了pom.xml文件。 - **自动化配置**:SpringBoot通过@...