美文网首页SpringBoot
关于SpringBoot2.x版本与1.5版本之间的问题(持续更

关于SpringBoot2.x版本与1.5版本之间的问题(持续更

作者: 意识流丶 | 来源:发表于2018-12-19 20:04 被阅读17次

    1.Social包在SpringBoot2.x移除问题

    spring-boot-autoconfigure1.5x版本中支持facebook,领英和推特
    官方文档:https://docs.spring.io/spring-boot/docs/1.5.18.RELEASE/api/

    image.png

    spring-boot-autoconfigure2.x中版本找不到了
    官方文档:https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/api/

    image.png

    问题:遇到SocialAutoConfigurerAdapterSocialPropertiesSocialWebAutoConfigurerAdapter类不存在

    解决方法:

    不想引入1.5版本的springboot的话只能自己按照源码重写(复制粘贴)
    SocialAutoConfigurerAdapter源码

    public abstract class SocialAutoConfigurerAdapter extends SocialConfigurerAdapter {
        public SocialAutoConfigurerAdapter() {
        }
        public void addConnectionFactories(ConnectionFactoryConfigurer configurer, Environment environment) {
            configurer.addConnectionFactory(this.createConnectionFactory());
        }
        protected abstract ConnectionFactory<?> createConnectionFactory();
    }
    

    SocialProperties源码

    public abstract class SocialProperties {
        private String appId;
        private String appSecret;
        public SocialProperties() {
        }
        public String getAppId() {
            return this.appId;
        }
        public void setAppId(String appId) {
            this.appId = appId;
        }
        public String getAppSecret() {
            return this.appSecret;
        }
        public void setAppSecret(String appSecret) {
            this.appSecret = appSecret;
        }
    }
    

    SocialWebAutoConfiguration源码

    @Configuration
    @ConditionalOnClass({ConnectController.class, SocialConfigurerAdapter.class})
    @ConditionalOnBean({ConnectionFactoryLocator.class, UsersConnectionRepository.class})
    @AutoConfigureBefore({ThymeleafAutoConfiguration.class})
    @AutoConfigureAfter({WebMvcAutoConfiguration.class})
    public class SocialWebAutoConfiguration {
        public SocialWebAutoConfiguration() {
        }
    
        private static class SecurityContextUserIdSource implements UserIdSource {
            private SecurityContextUserIdSource() {
            }
    
            public String getUserId() {
                SecurityContext context = SecurityContextHolder.getContext();
                Authentication authentication = context.getAuthentication();
                Assert.state(authentication != null, "Unable to get a ConnectionRepository: no user signed in");
                return authentication.getName();
            }
        }
    
        @Configuration
        @ConditionalOnClass({SpringResourceResourceResolver.class})
        protected static class SpringSocialThymeleafConfig {
            protected SpringSocialThymeleafConfig() {
            }
    
            @Bean
            @ConditionalOnMissingBean
            public SpringSocialDialect springSocialDialect() {
                return new SpringSocialDialect();
            }
        }
    
        @Configuration
        @EnableSocial
        @ConditionalOnWebApplication
        @ConditionalOnClass({SecurityContextHolder.class})
        protected static class AuthenticationUserIdSourceConfig extends SocialConfigurerAdapter {
            protected AuthenticationUserIdSourceConfig() {
            }
    
            public UserIdSource getUserIdSource() {
                return new SocialWebAutoConfiguration.SecurityContextUserIdSource();
            }
        }
    
        @Configuration
        @EnableSocial
        @ConditionalOnWebApplication
        @ConditionalOnMissingClass({"org.springframework.security.core.context.SecurityContextHolder"})
        protected static class AnonymousUserIdSourceConfig extends SocialConfigurerAdapter {
            protected AnonymousUserIdSourceConfig() {
            }
    
            public UserIdSource getUserIdSource() {
                return new UserIdSource() {
                    public String getUserId() {
                        return "anonymous";
                    }
                };
            }
        }
    
        @Configuration
        @EnableSocial
        @ConditionalOnWebApplication
        protected static class SocialAutoConfigurationAdapter extends SocialConfigurerAdapter {
            private final List<ConnectInterceptor<?>> connectInterceptors;
            private final List<DisconnectInterceptor<?>> disconnectInterceptors;
            private final List<ProviderSignInInterceptor<?>> signInInterceptors;
    
            public SocialAutoConfigurationAdapter(ObjectProvider<List<ConnectInterceptor<?>>> connectInterceptorsProvider, ObjectProvider<List<DisconnectInterceptor<?>>> disconnectInterceptorsProvider, ObjectProvider<List<ProviderSignInInterceptor<?>>> signInInterceptorsProvider) {
                this.connectInterceptors = (List)connectInterceptorsProvider.getIfAvailable();
                this.disconnectInterceptors = (List)disconnectInterceptorsProvider.getIfAvailable();
                this.signInInterceptors = (List)signInInterceptorsProvider.getIfAvailable();
            }
    
            @Bean
            @ConditionalOnMissingBean({ConnectController.class})
            public ConnectController connectController(ConnectionFactoryLocator factoryLocator, ConnectionRepository repository) {
                ConnectController controller = new ConnectController(factoryLocator, repository);
                if (!CollectionUtils.isEmpty(this.connectInterceptors)) {
                    controller.setConnectInterceptors(this.connectInterceptors);
                }
    
                if (!CollectionUtils.isEmpty(this.disconnectInterceptors)) {
                    controller.setDisconnectInterceptors(this.disconnectInterceptors);
                }
    
                return controller;
            }
    
            @Bean
            @ConditionalOnMissingBean
            @ConditionalOnProperty(
                prefix = "spring.social",
                name = {"auto-connection-views"}
            )
            public BeanNameViewResolver beanNameViewResolver() {
                BeanNameViewResolver viewResolver = new BeanNameViewResolver();
                viewResolver.setOrder(-2147483648);
                return viewResolver;
            }
    
            @Bean
            @ConditionalOnBean({SignInAdapter.class})
            @ConditionalOnMissingBean
            public ProviderSignInController signInController(ConnectionFactoryLocator factoryLocator, UsersConnectionRepository usersRepository, SignInAdapter signInAdapter) {
                ProviderSignInController controller = new ProviderSignInController(factoryLocator, usersRepository, signInAdapter);
                if (!CollectionUtils.isEmpty(this.signInInterceptors)) {
                    controller.setSignInInterceptors(this.signInInterceptors);
                }
    
                return controller;
            }
        }
    }
    

    2.Jdbc包在SpringBoot1.5和2.x之间的区别

    SpringBoot1.5源码中Jdbc包

    image.png

    SpringBoot2.x源码中Jdbc包

    image.png

    遇到的问题:DataSourceBuilder在SpringBoot2.x不存在

    解决方法:

    引入spring-boot-starter-jdbc依赖

    <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    

    源码对比

    SpringBoot1.5DataSourceBuilder 源码

    public class DataSourceBuilder {
        private static final String[] DATA_SOURCE_TYPE_NAMES = new String[]{"org.apache.tomcat.jdbc.pool.DataSource", "com.zaxxer.hikari.HikariDataSource", "org.apache.commons.dbcp.BasicDataSource", "org.apache.commons.dbcp2.BasicDataSource"};
        private Class<? extends DataSource> type;
        private ClassLoader classLoader;
        private Map<String, String> properties = new HashMap();
    
        public static DataSourceBuilder create() {
            return new DataSourceBuilder((ClassLoader)null);
        }
    
        public static DataSourceBuilder create(ClassLoader classLoader) {
            return new DataSourceBuilder(classLoader);
        }
    
        public DataSourceBuilder(ClassLoader classLoader) {
            this.classLoader = classLoader;
        }
    
        public DataSource build() {
            Class<? extends DataSource> type = this.getType();
            DataSource result = (DataSource)BeanUtils.instantiate(type);
            this.maybeGetDriverClassName();
            this.bind(result);
            return result;
        }
    
        private void maybeGetDriverClassName() {
            if (!this.properties.containsKey("driverClassName") && this.properties.containsKey("url")) {
                String url = (String)this.properties.get("url");
                String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
                this.properties.put("driverClassName", driverClass);
            }
    
        }
    
        private void bind(DataSource result) {
            MutablePropertyValues properties = new MutablePropertyValues(this.properties);
            (new RelaxedDataBinder(result)).withAlias("url", new String[]{"jdbcUrl"}).withAlias("username", new String[]{"user"}).bind(properties);
        }
    
        public DataSourceBuilder type(Class<? extends DataSource> type) {
            this.type = type;
            return this;
        }
    
        public DataSourceBuilder url(String url) {
            this.properties.put("url", url);
            return this;
        }
    
        public DataSourceBuilder driverClassName(String driverClassName) {
            this.properties.put("driverClassName", driverClassName);
            return this;
        }
    
        public DataSourceBuilder username(String username) {
            this.properties.put("username", username);
            return this;
        }
    
        public DataSourceBuilder password(String password) {
            this.properties.put("password", password);
            return this;
        }
    
        public Class<? extends DataSource> findType() {
            if (this.type != null) {
                return this.type;
            } else {
                String[] var1 = DATA_SOURCE_TYPE_NAMES;
                int var2 = var1.length;
                int var3 = 0;
    
                while(var3 < var2) {
                    String name = var1[var3];
    
                    try {
                        return ClassUtils.forName(name, this.classLoader);
                    } catch (Exception var6) {
                        ++var3;
                    }
                }
    
                return null;
            }
        }
    
        private Class<? extends DataSource> getType() {
            Class<? extends DataSource> type = this.findType();
            if (type != null) {
                return type;
            } else {
                throw new IllegalStateException("No supported DataSource type found");
            }
        }
    }
    

    SpringBoot2.xspring-boot-starter-jdbc依赖中DataSourceBuilder源码

    public final class DataSourceBuilder<T extends DataSource> {
        private static final String[] DATA_SOURCE_TYPE_NAMES = new String[]{"com.zaxxer.hikari.HikariDataSource", "org.apache.tomcat.jdbc.pool.DataSource", "org.apache.commons.dbcp2.BasicDataSource"};
        private Class<? extends DataSource> type;
        private ClassLoader classLoader;
        private Map<String, String> properties = new HashMap();
    
        public static DataSourceBuilder<?> create() {
            return new DataSourceBuilder((ClassLoader)null);
        }
    
        public static DataSourceBuilder<?> create(ClassLoader classLoader) {
            return new DataSourceBuilder(classLoader);
        }
    
        private DataSourceBuilder(ClassLoader classLoader) {
            this.classLoader = classLoader;
        }
    
        public T build() {
            Class<? extends DataSource> type = this.getType();
            DataSource result = (DataSource)BeanUtils.instantiateClass(type);
            this.maybeGetDriverClassName();
            this.bind(result);
            return result;
        }
    
        private void maybeGetDriverClassName() {
            if (!this.properties.containsKey("driverClassName") && this.properties.containsKey("url")) {
                String url = (String)this.properties.get("url");
                String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
                this.properties.put("driverClassName", driverClass);
            }
    
        }
    
        private void bind(DataSource result) {
            ConfigurationPropertySource source = new MapConfigurationPropertySource(this.properties);
            ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();
            aliases.addAliases("url", new String[]{"jdbc-url"});
            aliases.addAliases("username", new String[]{"user"});
            Binder binder = new Binder(new ConfigurationPropertySource[]{source.withAliases(aliases)});
            binder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(result));
        }
    
        public <D extends DataSource> DataSourceBuilder<D> type(Class<D> type) {
            this.type = type;
            return this;
        }
    
        public DataSourceBuilder<T> url(String url) {
            this.properties.put("url", url);
            return this;
        }
    
        public DataSourceBuilder<T> driverClassName(String driverClassName) {
            this.properties.put("driverClassName", driverClassName);
            return this;
        }
    
        public DataSourceBuilder<T> username(String username) {
            this.properties.put("username", username);
            return this;
        }
    
        public DataSourceBuilder<T> password(String password) {
            this.properties.put("password", password);
            return this;
        }
    
        public static Class<? extends DataSource> findType(ClassLoader classLoader) {
            String[] var1 = DATA_SOURCE_TYPE_NAMES;
            int var2 = var1.length;
            int var3 = 0;
    
            while(var3 < var2) {
                String name = var1[var3];
    
                try {
                    return ClassUtils.forName(name, classLoader);
                } catch (Exception var6) {
                    ++var3;
                }
            }
    
            return null;
        }
    
        private Class<? extends DataSource> getType() {
            Class<? extends DataSource> type = this.type != null ? this.type : findType(this.classLoader);
            if (type != null) {
                return type;
            } else {
                throw new IllegalStateException("No supported DataSource type found");
            }
        }
    }
    

    3.关于SpringDataJpa中findOne()方法报错问题

    报错信息Inferred type 'S' for type parameter 'S' is not within its bound;should extends xxxxxx

    解决方法:

    1.用回SpringBoot1.5
    2.findOne()改为findById().orElse(null)

    源码对比

    SpringBoot2.xspring-boot-starter-data-jpa依赖中的pom.xmlspring-data-jpa2.x.x

    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>2.1.3.RELEASE</version>
    

    CrudRepository源码

    @NoRepositoryBean
    public interface CrudRepository<T, ID> extends Repository<T, ID> {
        <S extends T> S save(S var1);
        <S extends T> Iterable<S> saveAll(Iterable<S> var1);
        Optional<T> findById(ID var1);
        boolean existsById(ID var1);
        Iterable<T> findAll();
        Iterable<T> findAllById(Iterable<ID> var1);
        long count();
        void deleteById(ID var1);
        void delete(T var1);
        void deleteAll(Iterable<? extends T> var1);
        void deleteAll();
    }
    

    SpringBoot1.5spring-boot-starter-data-jpa依赖中的pom.xmlspring-data-jpa1.x.x

    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.11.17.RELEASE</version>
    

    CrudRepository源码

    @NoRepositoryBean
    public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
        <S extends T> S save(S var1);
        <S extends T> Iterable<S> save(Iterable<S> var1);
        T findOne(ID var1);
        boolean exists(ID var1);
        Iterable<T> findAll();
        Iterable<T> findAll(Iterable<ID> var1);
        long count();
        void delete(ID var1);
        void delete(T var1);
        void delete(Iterable<? extends T> var1);
        void deleteAll();
    }
    

    区别:返回值由T变为Optional<T>,

    Optional类是Java8新特性类库:
    官方介绍:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

    Optional<T>源码

    public final class Optional<T> {
        private static final Optional<?> EMPTY = new Optional<>();
        private final T value;
    
        private Optional() {
            this.value = null;
        }
    
        public static<T> Optional<T> empty() {
            @SuppressWarnings("unchecked")
            Optional<T> t = (Optional<T>) EMPTY;
            return t;
        }
    
        private Optional(T value) {
            this.value = Objects.requireNonNull(value);
        }
    
        public static <T> Optional<T> of(T value) {
            return new Optional<>(value);
        }
    
        public static <T> Optional<T> ofNullable(T value) {
            return value == null ? empty() : of(value);
        }
    
        public T get() {
            if (value == null) {
                throw new NoSuchElementException("No value present");
            }
            return value;
        }
    
        public boolean isPresent() {
            return value != null;
        }
    
        public void ifPresent(Consumer<? super T> consumer) {
            if (value != null)
                consumer.accept(value);
        }
    
        public Optional<T> filter(Predicate<? super T> predicate) {
            Objects.requireNonNull(predicate);
            if (!isPresent())
                return this;
            else
                return predicate.test(value) ? this : empty();
        }
    
        public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
            Objects.requireNonNull(mapper);
            if (!isPresent())
                return empty();
            else {
                return Optional.ofNullable(mapper.apply(value));
            }
        }
    
        public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
            Objects.requireNonNull(mapper);
            if (!isPresent())
                return empty();
            else {
                return Objects.requireNonNull(mapper.apply(value));
            }
        }
    
        public T orElse(T other) {
            return value != null ? value : other;
        }
    
        public T orElseGet(Supplier<? extends T> other) {
            return value != null ? value : other.get();
        }
    
        public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
            if (value != null) {
                return value;
            } else {
                throw exceptionSupplier.get();
            }
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
    
            if (!(obj instanceof Optional)) {
                return false;
            }
    
            Optional<?> other = (Optional<?>) obj;
            return Objects.equals(value, other.value);
        }
    
        @Override
        public int hashCode() {
            return Objects.hashCode(value);
        }
    
        @Override
        public String toString() {
            return value != null
                ? String.format("Optional[%s]", value)
                : "Optional.empty";
        }
    }
    

    get()可以获取到值,但是直接这样写的话如果值不存在就要抛异常。所以要先做判断,值存在再get(),或者就是写在try-catch
    orElse(null)存在就会直接返回值,如果不存在会返回别的值,这里不存在返回的是null(可以给默认值)

    4.Elasticsearch与springboot集成的问题

    1.注释@Field的变化

    源码对比
    SpringBoot1.5

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    @Documented
    @Inherited
    public @interface Field {
        FieldType type() default FieldType.Auto;
        FieldIndex index() default FieldIndex.analyzed;
        DateFormat format() default DateFormat.none;
        String pattern() default "";
        boolean store() default false;
        String searchAnalyzer() default "";
        String analyzer() default "";
        String[] ignoreFields() default {};
        boolean includeInParent() default false;
    }
    

    SpringBoot2.x

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    @Documented
    @Inherited
    public @interface Field {
        FieldType type() default FieldType.Auto;
        boolean index() default true;
        DateFormat format() default DateFormat.none;
        String pattern() default "";
        boolean store() default false;
        boolean fielddata() default false;
        String searchAnalyzer() default "";
        String analyzer() default "";
        String normalizer() default "";
        String[] ignoreFields() default {};
        boolean includeInParent() default false;
        String[] copyTo() default {};
    }
    

    注解@Field的内置方法index()返回值由FieldIndex变为boolean

    2.FieldIndex枚举

    源码对比
    SpringBoot1.5

    public enum FieldIndex {
        not_analyzed,
        analyzed,
        no;
    
        private FieldIndex() {
        }
    }
    

    not_analyzed:整个字段存储为关键词,常用于汉字短语、邮箱等复杂的字符串;
    analyzed:通过默认的standard分析器进行分析,详细的分析规则参考这里
    no:无法通过检索查询到该字段;

    SpringBoot2.x

    public enum FieldType {
        Text,
        Integer,
        Long,
        Date,
        Float,
        Double,
        Boolean,
        Object,
        Auto,
        Nested,
        Ip,
        Attachment,
        Keyword;
    
        private FieldType() {
        }
    }
    

    3.在Elasticsearch与springboot集成中变化较大的还有Terms接口

    源码对比
    SpringBoot1.5

    public interface Terms extends MultiBucketsAggregation {
        List<Terms.Bucket> getBuckets();
        Terms.Bucket getBucketByKey(String var1);
        long getDocCountError();
        long getSumOfOtherDocCounts();
    
        public abstract static class Order implements ToXContent {
            public Order() {
            }
    
            public static Terms.Order count(boolean asc) {
                return asc ? InternalOrder.COUNT_ASC : InternalOrder.COUNT_DESC;
            }
    
            public static Terms.Order term(boolean asc) {
                return asc ? InternalOrder.TERM_ASC : InternalOrder.TERM_DESC;
            }
    
            public static Terms.Order aggregation(String path, boolean asc) {
                return new Aggregation(path, asc);
            }
    
            public static Terms.Order aggregation(String aggregationName, String metricName, boolean asc) {
                return new Aggregation(aggregationName + "." + metricName, asc);
            }
    
            public static Terms.Order compound(List<Terms.Order> orders) {
                return new CompoundOrder(orders);
            }
    
            public static Terms.Order compound(Terms.Order... orders) {
                return compound(Arrays.asList(orders));
            }
    
            protected abstract Comparator<Terms.Bucket> comparator(Aggregator var1);
    
            abstract byte id();
        }
    
        public abstract static class Bucket extends InternalBucket {
            public Bucket() {
            }
    
            public abstract Number getKeyAsNumber();
    
            abstract int compareTerm(Terms.Bucket var1);
    
            public abstract long getDocCountError();
        }
    
        public static enum ValueType {
            STRING(org.elasticsearch.search.aggregations.support.ValueType.STRING),
            LONG(org.elasticsearch.search.aggregations.support.ValueType.LONG),
            DOUBLE(org.elasticsearch.search.aggregations.support.ValueType.DOUBLE);
    
            final org.elasticsearch.search.aggregations.support.ValueType scriptValueType;
    
            private ValueType(org.elasticsearch.search.aggregations.support.ValueType scriptValueType) {
                this.scriptValueType = scriptValueType;
            }
    
            static Terms.ValueType resolveType(String type) {
                if ("string".equals(type)) {
                    return STRING;
                } else if (!"double".equals(type) && !"float".equals(type)) {
                    return !"long".equals(type) && !"integer".equals(type) && !"short".equals(type) && !"byte".equals(type) ? null : LONG;
                } else {
                    return DOUBLE;
                }
            }
        }
    }
    

    SpringBoot2.x

    public interface Terms extends MultiBucketsAggregation {
        List<? extends Terms.Bucket> getBuckets();
    
        Terms.Bucket getBucketByKey(String var1);
    
        long getDocCountError();
    
        long getSumOfOtherDocCounts();
    
        public interface Bucket extends org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket {
            Number getKeyAsNumber();
    
            long getDocCountError();
        }
    }
    
    可以发现内部类Order并没有在Terms中,而是变成了抽象类BucketOrder
    public abstract class BucketOrder implements ToXContentObject, Writeable {
        public BucketOrder() {
        }
    
        public static BucketOrder count(boolean asc) {
            return asc ? InternalOrder.COUNT_ASC : InternalOrder.COUNT_DESC;
        }
    
        public static BucketOrder key(boolean asc) {
            return asc ? InternalOrder.KEY_ASC : InternalOrder.KEY_DESC;
        }
    
        public static BucketOrder aggregation(String path, boolean asc) {
            return new Aggregation(path, asc);
        }
    
        public static BucketOrder aggregation(String path, String metricName, boolean asc) {
            return new Aggregation(path + "." + metricName, asc);
        }
    
        public static BucketOrder compound(List<BucketOrder> orders) {
            return new CompoundOrder(orders);
        }
    
        public static BucketOrder compound(BucketOrder... orders) {
            return compound(Arrays.asList(orders));
        }
    
        public abstract Comparator<Bucket> comparator(Aggregator var1);
    
        abstract byte id();
    
        public abstract int hashCode();
    
        public abstract boolean equals(Object var1);
    
        public void writeTo(StreamOutput out) throws IOException {
            Streams.writeOrder(this, out);
        }
    
        public String toString() {
            return Strings.toString(this);
        }
    }
    

    在聚合查询中SpringBoot1.5用Terms.Order.count()是没问题的,在SpringBoot2.x中需要改成BucketOrder.count()

    相关文章

      网友评论

        本文标题:关于SpringBoot2.x版本与1.5版本之间的问题(持续更

        本文链接:https://www.haomeiwen.com/subject/alkskqtx.html