springboot 1.5.x与2.x.x区别

具体的差异
参考官方:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide
中文版

这里只是稍微记录一下我学习看到的
一.@SpringBootApplication
修饰主程序类。可以通过main方法启动项目
单个注释可用于启用这三个功能,即:@SpringBootApplication
@EnableAutoConfiguration:启用弹簧启动的自动配置机制
@ComponentScan: 在应用程序所在的包上启用扫描
@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类

下面展示1.5.9与2.0的区别

SpringBootApplication修饰的类的,这里仅以web为例
1.5.9版本的,自动配置类96,最后过程为20
2.1.8版本的,自动配置类117,最后过滤为22
加载的时候,是先加载自动配置类,再获取主程序main所在的包;
1.5.9的
采用的java逐注解,替代了配置文件;
4.@SpringBootApplication中
    @SpringBootConfiguration
        @Configuration(spring的注解)
            @Component组件
    @EnableAutoConfiguration  通过这个注解名就可以直接找到spring.factories中的EnableAutoConfiguration对应的组件
        @AutoConfigurationPackage
            @Import(AutoConfigurationPackages.Registrar.class)
            Registrar作用:将主配置类@SpringBootApplication修饰的类所在的包及子包里面的所有组件扫描到spring容器中;
            所以需要将controller或者service类要放在主配置类所在包内才能生效;
        @Import({EnableAutoConfigurationImportSelector.class})
            作用:获取当前环境需要哪些自动组件,全部把这些自动配置类导入容器中;一开始是获取所有的96个自动配置类全名,最后过滤为20个(当前应用场景)
            具体是在META-INF/spring.factories这个配置文件下;EnableAutoConfiguration/中
            位置:
            (AutoConfigurationImportSelector.selectImports().中的getCandidateConfigurations())
            对应spring-boot-autoconfigure-1.5.9.RELEASE.jar;
        import:spring注解,给容器导入组件
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
该注解标识的类, 会被 Spring 自动扫描并且装入bean容器


protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
				getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
		Assert.notEmpty(configurations,
				"No auto configuration classes found in META-INF/spring.factories. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

传入的是EnableAutoConfiguration.class;
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }

            return result;
        } catch (IOException var8) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
        }
    }


2.0以后的
2.1.9最新
在boot2.0之前.获取配置文件中的自动配置类是没有缓存的,在2.0加入了缓存

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
			getBeanClassLoader());
	Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
			+ "are using a custom packaging, make sure that file is correct.");
	return configurations;
}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
	return EnableAutoConfiguration.class;
}

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
	}

	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryClassName = ((String) entry.getKey()).trim();
					for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

二.日志框架
spring默认的是jcl+log4j
而spring boot是slf4+logback,
在spring 5的时候.jcl不在放在核心包中,而是独立了出来,并且默认排除了log4j;
这样在spring boot2.0引入日志包的时候,引用是不一样的;

三.静态资源访问
资源管理:
1)、所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;
http://localhost:8080/webjars/jquery/3.4.1/jquery.js
2)、"/**" 访问当前项目的任何资源,都去(静态资源的文件夹)找映射
“classpath:/META‐INF/resources/”,
“classpath:/resources/”,
“classpath:/static/”,
“classpath:/public/”
“/”:当前项目的根路径
相同的资源,访问优先级"classpath:/resources/", “classpath:/static/”, “classpath:/public/” }

在spring boot 1.5.x中,resources/static等目录下的静态资源可以直接访问,并且访问路径上不用带static;
 * 如:
 * http://localhost:8080/asserts/css/signin.css
 * http://localhost:8080/webjars/bootstrap/4.3.1/css/bootstrap.css
 *
 * 在2.0中需要手动添加静态资源拦截路径
 * SpringBoot2+中要排除静态资源路径, 因访问时默认会加/static,
 *
 * 解决方法1:因静态资源的默认目录为resources,static,public等目录
 * 那么在写除外路径的时候,不需要带上这个目录前缀static,页面引用资源链接访问也不需要加这个目录static;
 * @Override
            public void addInterceptors(InterceptorRegistry registry) {
                //springmvc需要手动处理
                registry.addInterceptor(new loginHandleInterceptor()).addPathPatterns("/**")
                        .excludePathPatterns("/","/index.html","/user/login")
                        .excludePathPatterns("/asserts/**","/webjars/**"); //静态资源在2.0需要是手动排除
                //排除登陆页面的请求连接
            }
 *
 * 解决方法2:
 *自定义静态资源目录  配置spring.mvc.static-path-pattern=/static/**
 * 这样就写除外路径的时候就可以直接写/static/**,但是资源链接访问的是需要加/static目录的
 *  @Override
            public void addInterceptors(InterceptorRegistry registry) {
                //springmvc需要手动处理
                registry.addInterceptor(new loginHandleInterceptor()).addPathPatterns("/**")
                        .excludePathPatterns("/","/index.html","/user/login")
                        .excludePathPatterns("/static/**"); //静态资源在2.0需要是手动排除
                //排除登陆页面的请求连接
            }

四.异常处理


package com.ysy.component;

import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;

import java.util.Map;
/*在1.5.9版本,org.springframework.boot.autoconfigure.web.DefaultErrorAttributes;中
* 	@Override
	public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
			boolean includeStackTrace) {
		Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
		errorAttributes.put("timestamp", new Date());
		addStatus(errorAttributes, requestAttributes);
		addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
		addPath(errorAttributes, requestAttributes);
		return errorAttributes;
	}
* */
//在2.0版本,  org.springframework.boot.web.servlet.error.DefaultErrorAttributes;中
/*
* @Override
	public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
		Map<String, Object> errorAttributes = new LinkedHashMap<>();
		errorAttributes.put("timestamp", new Date());
		addStatus(errorAttributes, webRequest);
		addErrorDetails(errorAttributes, webRequest, includeStackTrace);
		addPath(errorAttributes, webRequest);
		return errorAttributes;
	}
* */

//给容器中加入我们自己定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {

   /* //返回值的map就是页面和json能获取的所有字段
    //1.5.9版本
    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
        map.put("company","atguigu");

        //我们的异常处理器携带的数据
        Map<String,Object> ext = (Map<String, Object>) requestAttributes.getAttribute("ext", 0);
        map.put("ext",ext);
        return map;
    }*/

   //2.1.8版本
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
        map.put("company","atguigu");

        //我们的异常处理器携带的数据
        Map<String,Object> ext = (Map<String, Object>) webRequest.getAttribute("ext", 0);
        map.put("ext",ext);
        return map;
    }
}


五.内置容器如tomcat的配置修改
配置文件的定义没有变化,但是通知定制器修改发生了变化

     //Spring Boot 1.x:
     /*   @Bean //一定要将这个定制器加入到容器中,对于所有容器生效
        public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {
            return new EmbeddedServletContainerCustomizer() {
                //定制嵌入式的Servlet容器相关的规则
                @Override
                public void customize(ConfigurableEmbeddedServletContainer container) {
                    container.setPort(8083);
                }
            };
        }*/
    //在2.x版本改为实现 WebServerFactoryCustomizer 接口的 customize 方法
        @Bean
        public WebServerFactoryCustomizer webServerFactoryCustomizer() {
            return new WebServerFactoryCustomizer() {
                @Override
                public void customize(WebServerFactory factory) {
                    ConfigurableWebServerFactory serverFactory =
                            (ConfigurableWebServerFactory)factory;
                    //配置优先级高于配置文件
                    serverFactory.setPort(8081);
                }
            };
        }
        
       //优化写法
      @Bean
      public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
          //WebServerFactoryCustomizer<ConfigurableWebServerFactory> factory = f -> f.setPort(8085);
          //return factory;
          //最简写法   配置优先级高于配置文件
          return f -> f.setPort(8085);
      };

再看看定制器

1.5.9
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties
		implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {

	/**
	 * Server HTTP port.
	 */
	private Integer port;

在2.0.x   去掉了EmbeddedServletContainerCustomizer,取而代之的是WebServerFactoryCustomizer(函数式接口)
@FunctionalInterface
public interface WebServerFactoryCustomizer<T extends WebServerFactory> {

	/**
	 * Customize the specified {@link WebServerFactory}.
	 * @param factory the web server factory to customize
	 */
	void customize(T factory);
}

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

	/**
	 * Server HTTP port.
	 */
	private Integer port;

再看看2个版本的目录结构也不一样:
1.5.9的定制器EmbeddedServletContainerCustomizer目录
在这里插入图片描述
这里比如具体的tomcat配置:
基于EmbeddedServletContainerFactory接口
TomcatEmbeddedServletContainerFactory
在这里插入图片描述
自动配置类:EmbeddedServletContainerAutoConfiguration

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {

	/**
	 * Nested configuration if Tomcat is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedTomcat {

2.1.8的
定制器WebServerFactoryCustomizer的目录
在这里插入图片描述
这里比如具体的tomcat配置:,基于WebServerFactory接口
TomcatServletWebServerFactory
在这里插入图片描述
自动配置类应该是:ServletWebServerFactoryAutoConfiguration

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
		return new ServletWebServerFactoryCustomizer(serverProperties);
	}

六.默认的连接池发生了变化
性能方面 HikariCP>Druid>tomcat-jdbc>dbcp>c3p0
1.5.9的是tomcat的,2.0.x的是HikariCP
我这里使用的oracle 12c,注意
1.5.9版本的跟2.0.x之后的驱动名不一样:

spring:
  datasource:
    username: xiaoming
    password: 123456
    url: jdbc:oracle:thin:@localhost:1521:orcltest
2.0.x的是      driver-class-name: oracle.jdbc.OracleDriver
#1.5.9的是    driver-class-name: oracle.jdbc.driver.OracleDriver
依赖
   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>12.2.0.1</version>
        </dependency>
测试代码
@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot159ApplicationTests {
  Logger log= LoggerFactory.getLogger(getClass());

    @Autowired
    DataSource dataSource;
    @Test
    public void contextLoads() throws SQLException {

        System.out.println(dataSource.getClass());
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }

}

展示:
1.5.9
2019-10-05 15:16:28.664  INFO 4536 --- [           main] com.ysy.Springboot159ApplicationTests    : info
class org.apache.tomcat.jdbc.pool.DataSource
ProxyConnection[PooledConnection[oracle.jdbc.driver.T4CConnection@4364863]]

2.1.9的
HikariProxyConnection@1139915666 wrapping oracle.jdbc.driver.T4CConnection@3727f0ee

1.5.9的依赖
在这里插入图片描述
2.1.9的依赖
在这里插入图片描述
七,启动配置原理
关键的几个类
ApplicationContextInitializer
SpringApplicationRunListener
ApplicationRunner
CommandLineRunner

1.5.9的

public static ConfigurableApplicationContext run(Object source, String... args) {
		return run(new Object[] { source }, args);
	}
	然后调用SpringApplication.initialize方法
	private void initialize(Object[] sources) {
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
		this.webEnvironment = deduceWebEnvironment();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
	
然后调用SpringApplication的
public ConfigurableApplicationContext run(String... args) {

2.1.9的,类似

SpringApplication下
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}
	SpringApplication下
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值