SpringBoot

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

2018-12-19  本文已影响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()

上一篇下一篇

猜你喜欢

热点阅读