Spring Boot

Spring Boot

简述Spring Boot是什么以及Spring Boot能做什么,最后来写自己的starter来支持Spring Boot自动配置,探索Spring Boot为何如此聪明。


简介

Spring Boot 提供约定优于配置的快速构建Spring应用,简单来讲就是快速构建和运行Spring应用。
Spring Boot很容易创建独立的生产级的Spring应用,大多数Spring Boot应用需要非常少的Spring 配置。

特性

  • 创建独立运行的spring应用
  • 直接嵌入Tomcat、Jetty或者Undertow web 容器使得不需要部署war包
  • 提供starter来简化maven配置
  • 尽可能的自动化配置应用
  • 提供了生成级指标检测、健康状况检查支持外部化配置
  • 没有代码生成、没有xml配置要求

快速开始

  • 加入maven依赖
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.3.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
  • SampleController
package hello;

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;

@Controller
@EnableAutoConfiguration
public class SampleController {

    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SampleController.class, args);
    }
}

直接运行此SampleController。
如此简单的一个Spring Web应用就在tomcat 8080 启动了,而不需要任何额外的配置。
相信应该已经明白Spring Boot是什么以及可以干什么了。

配置

尽管Spring Boot 如此聪明的自动化配置了,但如果想自定义配置,可以通过/src/main/resources/application.properties(或者application.yml)来配置,下面提供几个简单常用的配置:

项目配置
容器监听端口server.port = 8090
数据库连接URLspring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
redis服务器地址spring.redis.host=127.0.0.1
activemq服务器地址spring.activemq.broker-url=tcp://127.0.0.1:61616

官方文档提供了所有配置参考,请参考[Spring Boot Reference#appendix]

Spring Boot为何如此聪明

如果将Jetty的依赖加入到maven配置中,再启动应用就会使用Jetty来启动我们的应用,Spring Boot为何如此聪明?
真相是在Spring Boot启动时会扫描classpath下所有/META-INF/spring.factories文件,此文件里描述了所有自动配置的项目,这里提供Spring Boot自身的/META-INF/spring.factories片段,位于spring-boot-autoconfigure-version.jar中:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

可以看到以上片段包含了amqp、cache、jpa、mongo、redis、es以及大部分web自动配置,Spring Boot就是通过这些XXAutoConfiguration类来聪明的自动化配置,这些XXAutoConfiguration可以根据环境动态配置所需要的Bean(其他资源),这些XXAutoConfiguration本身就是标准的Java based Configuration(@Configuration),依靠条件动态配置bean:
* @ConditionalOnClass
* @ConditionalOnMissingBean
* @ConditionalOnProperty

Spring Boot处理静态资源

Spring Boot 默认从classpath的/static、 /public 、 /resources 或者 /META-INF/resources或者ServletContext的/服务静态资源。
静态资源
如上述目录结构,访问静态资源分别为:
- /src/main/resources/resources/index.html:http://127.0.0.1:8080/或者http://127.0.0.1:8080/index.html
- /src/main/resources/static/2.jpg:http://127.0.0.1:8080/2.jpg
- /src/main/resources/public/3.jpg:http://127.0.0.1:8080/3.jpg

Spring Boot 试用Spring MVC 的ResourceHttpRequestHandler ,可以添加WebMvcConfigurerAdapter 的实现复写addResourceHandlers 方法来修改这些默认配置。
你可以通过application.properties的spring.resources.static-locations属性自定义静态资源目录位置。
默认配置为:spring.resources.static-locations =
classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/.
可以建立/src/main/resources/cust,并放入index.html和1.jpg
application.properties中配置spring.resources.static-locations = classpath:/cust/(注意一定要加classpath:,并且路径一定是目录而非文件,是/cust/而非/cust)
如此可以使用http://127.0.0.1:8080/index.htmlhttp://127.0.0.1:8080/1.jpg来访问上述资源了。

Spring Boot错误处理

Spring Boot 注册了一个容器全局的错误页,/error
对于为机器的客户返回JSON格式的错误信息,http状态吗和错误信息,对于浏览器以html格式返回同样的错误信息,要完全替换这些机制需要注册一个bean实现ErrorController 接口即可。
如果想返回新的ContentType类型的错误信息BasicErrorController 是特别有用的,继承新加一个@RequestMapping方法produces 为新ContentType即可。

如果想自定义错误页,需要在/public 或者/static新建error目录创建404.html 或者5xx.html这样以http状态码的错误页面,既可以是普通的html也可以是模版。
对于复杂的映射你也可以新加一个bean去实现ErrorViewResolver 接口。

Spring Boot Starters

Spring Boot提供了许多starter来简化maven配置,自动化配置,这些*AutoConfiguration大都在Spring Boot提供的starter pom中,同样包含/META-INF/spring.factories文件,
详情参考[Spring Boot Starters#using-boot-starter]

spring-boot-starter-mail
spring-boot-starter-activemq
spring-boot-starter-web
spring-boot-starter-jdbc
spring-boot-starter-amqp
spring-boot-starter-redis
spring-boot-starter-data-mongodb

自定义spring-boot-starter-xxx

Spring Boot支持自定义自己的starter来自动化配置,需要配置/META-INF/spring.factoriesXXAutoConfiguration
下面来自定义starter,实现的功能为:如果spring bean的某个属性加了@Reference注解、并且该属性是接口类型的话,就为该属性自动注入一个代理对象。

创建mavne项目

加入Spring Boot 依赖

<groupId>org.pretent.open</groupId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>spring-boot-starter-mrpc</artifactId>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>1.4.2.RELEASE</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

创建AutoConfiguration

程序清单:
MrpcAutoConfiguration.java

package org.pretent.mrpc.support.spring.boot;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MrpcAutoConfiguration {

    @Bean
    public InjectBean mInjectBean() {
        return new InjectBean();
    }

    @Bean
    public MrpcBootRegisterBean mMrpcBeanFactory() {
        MrpcBootRegisterBean mrpcBeanFactory = new MrpcBootRegisterBean();
        return mrpcBeanFactory;
    }
}

InjectBean.java

public class InjectBean {

    public InjectBean() {
    }

    public synchronized void inject(Object bean) {
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.getType().isInterface()) {
                Reference reference = field.getAnnotation(Reference.class);
                if (reference != null) {
                    try {
                        field.setAccessible(true);
                        Object value = field.get(bean);
                        field.setAccessible(false);
                        if (value == null) {
                        // 通过代理生成接口代理对象
                value = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{field.getType()}, new MInvocationHandler());
                            if (value != null) {
                                field.setAccessible(true);
                                field.set(bean, value);
                                field.setAccessible(false);
                            }
                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

MrpcBootRegisterBean .java

public class MrpcBootRegisterBean implements BeanPostProcessor {

    @Autowired
    private InjectBean injectBean ;

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // annotation @reference
        injectBean.inject(bean);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

MInvocationHandler.java

class MInvocationHandler implements InvocationHandler{

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 代理对象对于每个方法调用都返回proxy字符串,没有实际意义
        return "proxy";
    }

}

Reference.java

@Target(value = {ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Reference {
}

注册/META-INF/spring.factories

建立 /src/main/resources/META-INF/spring.factories
写入

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.pretent.mrpc.support.spring.boot.MrpcAutoConfiguration

安装自定义的starter

$ mvn clean install

使用自定义的starter

创建maven项目加入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.2.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.pretent.open</groupId>
        <artifactId>spring-boot-starter-mrpc</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

程序清单:
SampleController .java

@Controller
public class SampleController {

    @Reference
    private UserService userService;

    @RequestMapping("/")
    @ResponseBody
    String home() throws Exception {
        return userService.say(new Person(22, "张三", 22, new Date())) ;
    }

}

UserService .java

public interface UserService {
    String say(Person person) throws Exception;
}

Application.java

@SpringBootApplication
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

启动应用浏览器访问http://localhost:8080/,可以看到我们的userService已经被赋值为代理对象,并且返回’proxy’了。

以上自定义spring-boot-starters 在我的rpc框架中有使用到,如果需要可以参考 https://github.com/pretent/mrpc

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值