Я нашел решение для использования spring-cloud-zookeeper без Spring Boot, основываясь на представленной здесь идее https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html
Его следует легко обновить в соответствии с вашими потребностями и использовать сервер Spring Cloud Config (необходимо обновить класс CloudEnvironement, чтобы загрузить файл с сервера вместо Zookeeper)
Сначала создайте класс CloudEnvironement, который будет создайте PropertySource (например, из Zookeeper):
CloudEnvironement.java
public class CloudEnvironment extends StandardServletEnvironment {
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
super.customizePropertySources(propertySources);
try {
propertySources.addLast(initConfigServicePropertySourceLocator(this));
}
catch (Exception ex) {
logger.warn("failed to initialize cloud config environment", ex);
}
}
private PropertySource> initConfigServicePropertySourceLocator(Environment environment) {
ZookeeperConfigProperties configProp = new ZookeeperConfigProperties();
ZookeeperProperties props = new ZookeeperProperties();
props.setConnectString("myzookeeper:2181");
CuratorFramework fwk = curatorFramework(exponentialBackoffRetry(props), props);
ZookeeperPropertySourceLocator propertySourceLocator = new ZookeeperPropertySourceLocator(fwk, configProp);
PropertySource> source= propertySourceLocator.locate(environment);
return source ;
}
private CuratorFramework curatorFramework(RetryPolicy retryPolicy, ZookeeperProperties properties) {
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();
builder.connectString(properties.getConnectString());
CuratorFramework curator = builder.retryPolicy(retryPolicy).build();
curator.start();
try {
curator.blockUntilConnected(properties.getBlockUntilConnectedWait(), properties.getBlockUntilConnectedUnit());
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return curator;
}
private RetryPolicy exponentialBackoffRetry(ZookeeperProperties properties) {
return new ExponentialBackoffRetry(properties.getBaseSleepTimeMs(),
properties.getMaxRetries(),
properties.getMaxSleepMs());
}
}
Затем создайте собственный класс XmlWebApplicationContext: он позволит загружать PropertySource из Zookeeper, когда запустите ваше веб-приложение и замените магию начальной загрузки Spring Boot:
MyConfigurableWebApplicationContext.java
public class MyConfigurableWebApplicationContext extends XmlWebApplicationContext {
@Override
protected ConfigurableEnvironment createEnvironment() {
return new CloudEnvironment();
}
}
Последняя, в вашем файле web.xml добавьте следующий контекстный параметр для использования вашего класса MyConfigurableWebApplicationContext и начальной загрузки вашего CloudEnvironement.
contextClass
com.kiabi.config.MyConfigurableWebApplicationContext
Если вы используете стандартный конфигуратор файлов свойств, он все равно должен быть загружен, чтобы вы могли иметь свойства как в локальном файле, так и в Zookeeper.
Чтобы все это работало, вам нужно иметь в своем classpath файлы spring-cloud-starter-zookeeper-config и curator-framework jar с их зависимостью. Если вы используете maven, вы можете добавить следующее в pom.xml
org.springframework.cloud
spring-cloud-zookeeper-dependencies
1.1.1.RELEASE
pom
import
org.springframework.cloud
spring-cloud-starter-zookeeper-config
org.apache.curator
curator-framework
Я считаю, что A должно быть пространством имен, а не структурой.
Помещение перечислений в глобальную область видимости слишком открыто, размещение их в классе может привести к нежелательной зависимости. Для того, чтобы перечисление не было тесно связано с классом, я использую следующее:
#define CLEANENUMS_BEGIN(name) namespace name { typedef enum {
#define CLEANENUMS_END(name) } internal_ ## name ## _e;} typedef name::internal_ ## name ## _e name ## _e;
Затем вы можете использовать в глобальной области:
CLEANENUMS_BEGIN(myEnum)
horizontal,
vertical,
CLEANENUMS_END(myEnum)
Это более или менее имитирует способ C # обработки области действия перечислений. Препроцессор выдаст следующий код:
namespace myEnum
{
enum internal_myEnum_e
{
horizontal,
vertical,
}
}
typedef internal_myEnum_e myEnum_e;
Затем на данное перечисление будет ссылаться как
myEnum_e val = myEnum::horizontal;
. Надеюсь, есть лучший способ сделать это, но пока это единственное решение, которое я нашел.
Why do you even have the test method in struct B? I don't think it makes any sense.
By defining struct A and defining an enum inside it, you are more or less saying that "here's an enum in scope of struct A" and this is the same as saying "if you want to use this enum, you have to refer to the struct A".
Putting the enum inside a namespace will not solve your problem. Because you will have the same scope problem (C4482)
I think you are making things too complicated. What do you think of this?
struct A
{
enum A_enum
{
E0,
E1,
E2
};
static bool test(A_enum val)
{
return (val == E1);
}
};
int main()
{
assert(A::test(A::E1));
return 0;
}
Note that A::test() is static. It should be because you aren't operating on the struct state. And since it's static, you dont need an instance of A to call the method.
I've had the same issue in the past, and this is how I've fixed it. I wanted to be able to switch the implementation of a library at compile time. Одна из библиотек использовала такой код:
namespace Lib1
{
enum LibEnum { One, Two, Three };
[...]
void someFunc(LibEnum val);
}
В моем коде я хотел скрыть реализацию библиотеки от взаимодействия с пользователем (поэтому пользователь моего кода никогда не должен видеть, какую библиотеку я использую внутри):
Решение 1:
namespace MyCode
{
// Example to avoid copying a function from Lib1 here
typedef Lib1::someFunc aFunctionImUsing;
// This doesn't work
// typedef LibEnum MyEnum;
// As such code doesn't compile:
// aFunctionImUsing(One); // Error unknown identifier One
// But this did:
struct Type
{
enum MyType { One = Lib1::One, Two = Lib1::Two, Three = Lib1::Three };
}
static inline Lib1::LibEnum as(Type::MyType t) { return (Lib1::LibEnum)t; }
// Now code like this compiles:
aFunctionImUsing(as(Type::One));
// This one doesn't:
// aFunctionImUsing(Type::One); // Can't convert from Type::MyType to Lib1::LibEnum
[...]
}
Решение 2:
namespace MyCode
{
struct Type
{
enum MyType { One = Lib1::One, Two = Lib1::Two, Three = Lib1::Three };
}
// If you don't care about polluting your namespace with numerous wrapper
// you can write this instead of typedef someFunc:
static inline void myFunc(Type::MyType t) { return Lib1::someFunc((Lib1::LibEnum)t); }
// This one does:
myFunc(Type::One);
[...]
}
Это 2 проблемы с фрагментом кода выше. Первая проблема заключается в том, что вы должны скопировать и вставить перечисление в свое пространство имен (но с простым регулярным выражением в поиске и замене все готово). Вторая проблема заключается в том, что ваш пользователь должен будет использовать метод «as», что означает, что это непросто, или вам придется обернуть метод / функцию, используя второе решение.
В любом случае, поскольку невозможно ввести enum в пространстве имен, это лучшее решение, которое вы можете сделать. Обратите внимание, что ваш пользователь кода даже не знает, что вы используете библиотеку Lib1 в примере кода.