由于项目使用apache eagle框架,所以学习了一下代码结构。由于还不会java,所以看得很艰难,只能大体先猜测了代码主结构,可能下面说的有不对的地方,望见谅。
页面保存出错,编辑了好几遍,格式太难调了,不调了。。。凑合看吧,想看带彩色的在编译器里看吧,页面实在调不出来了。
官方文档在:http://eagle.apache.org/docs/latest/getting-started/
源码中文档在E:\code\eagle\eagle-master-0.5.0-SNAPSHOT\docs\docs\目录下。
使用了Dropwizard框架,框架的文档在:https://www.dropwizard.io/0.7.1/docs/manual/core.html#bundles
目录
a)GuiceBundleLoader.load()注册所有的Module
ApplicationProviderServiceImpl
ServerModule
ApplicationGuiceModule
ModuleRegistry
b)EntityRepositoryScanner注册所有的Entity
EntityRepository repo
EntityDefinitionManager.registerEntity
jersey().register注册REST接口对应的resources
一、相关操作使用rest接口进行
例如启动一个app
E:\code\eagle\eagle-master-0.5.0-SNAPSHOT\eagle-security\eagle-security-hdfs-auditlog\README.md
二、eagle-server.sh启动脚本
E:\code\eagle\eagle-master-0.5.0-SNAPSHOT\eagle-assembly\src\main\bin\eagle-server.sh
PROGRAM="java $JVM_OPTS -cp $EAGLE_CLASSPATH org.apache.eagle.server.ServerMain server ${CONFIGURATION_YML}"
org.apache.eagle.server.ServerMain就是主入口
三、ServerMain.java程序主入口
E:\code\eagle\eagle-master-0.5.0-SNAPSHOT\eagle-server\src\main\java\org\apache\eagle\server\ServerMain.java
main函数
System.out.println("\nStarting Eagle Server ...\n");
try {
new ServerApplication().run(args);
}
1、ServerApplication
1)initialize函数
LOG.debug("Loading and registering guice bundle");
GuiceBundle<ServerConfig> guiceBundle = GuiceBundleLoader.load();
bootstrap.addBundle(guiceBundle);
LOG.debug("Loading and registering static AssetsBundle on /assets");
bootstrap.addBundle(new AssetsBundle("/assets", "/", "index.html", "/"));
LOG.debug("Initializing guice injector context for current ServerApplication");
guiceBundle.getInjector().injectMembers(this);
EntityRepositoryScanner.scan();
a)GuiceBundleLoader.load()注册所有的Module
public static GuiceBundle<ServerConfig> load(List<Module> modules) {
/*
We use tow injectors, one is Dropwizard injector, the other injector is to instantiate ApplicationProvider and load sub modules from applications
so we need make Config and ApplicationProviderServiceImpl to have a global instance across multiple injectors
*/
// Eagle server module
Config config = ConfigFactory.load();
ApplicationProviderService appProviderSvc = new ApplicationProviderServiceImpl[c2] (config);
ServerModule serveBaseModule = new ServerModule[c3] (appProviderSvc);
// load application specific modules
ModuleRegistry registry = ApplicationExtensionLoader.load(serveBaseModule);
// add application specific modules
MetadataStore metadataStoreModule = MetadataStoreModuleFactory.getModule[c4] ();
List<Module> metadataExtensions = metadataStoreModule.getModules(registry);
int extensionNum = 0;
GuiceBundle.Builder<ServerConfig> builder = GuiceBundle.newBuilder();
if (metadataExtensions != null) {
extensionNum = metadataExtensions.size();
metadataExtensions.forEach(builder::addModule);
}
LOGGER.warn("Loaded {} modules (scope: metadataStore)", extensionNum);
List<Module> globalExtensions = registry.getModules(GlobalScope.class);
extensionNum = 0;
if (globalExtensions != null) {
extensionNum = globalExtensions.size();
globalExtensions.forEach(builder::addModule);
}
LOGGER.warn("Loaded {} modules (scope: global)", extensionNum);
if (modules != null) {
modules.forEach(builder::addModule);
}
return builder.addModule(serveBaseModule)
.setConfigClass(ServerConfig.class)
.build();
}
[c2]返回provider,代码看应该是获取要启动的Application
如后面ApplicationProviderServiceImpl的代码
代码中要求匹配到配置文件中的application.provider.load,但配置文件中只对应到application里可能类似的一个是:
stream {
provider = org.apache.eagle.app.messaging.KafkaStreamProvider
}
[c4]从配置文件中读取数据库的类型,返回的就是JDBCMetadataStore类的实例
ApplicationProviderServiceImpl
public ApplicationProviderServiceImpl(Config config) {
LOG.warn("Initializing {}", this.getClass().getCanonicalName());
this.config = config;
String appProviderLoaderClass = this.config.hasPath(APP_PROVIDER_LOADER_CLASS_KEY)
? this.config.getString(APP_PROVIDER_LOADER_CLASS_KEY) : ApplicationProviderLoader.getDefaultAppProviderLoader[c5] ();
LOG.warn("Initializing {} = {}", APP_PROVIDER_LOADER_CLASS_KEY, appProviderLoaderClass);
appProviderLoader = initializeAppProviderLoader(appProviderLoaderClass);
LOG.warn("Initialized {}", appProviderLoader);
reload();
}
[c5]对应的provider.xml文件里的类是TestStormApplication
ServerModule
public class ServerModule extends AbstractModule {
private ApplicationProviderService appProviderInst;
public ServerModule(ApplicationProviderService appProviderInst) {
this.appProviderInst = appProviderInst;
}
@Override
protected void configure() {
install(new CommonGuiceModule());
install(new ApplicationGuiceModule(appProviderInst));
install(MetadataStoreModuleFactory.getModule());
}
}
ApplicationGuiceModule
public class ApplicationGuiceModule extends AbstractModule {
private final ApplicationProviderService appProviderInst;
public ApplicationGuiceModule(ApplicationProviderService appProviderInst) {
this.appProviderInst = appProviderInst;
}
public ApplicationGuiceModule() {
this.appProviderInst = new ApplicationProviderServiceImpl(ConfigFactory.load());
}
@Override
protected void configure() {
bind(ApplicationProviderService.class).toProvider(Providers.of(appProviderInst));
bind(ApplicationDescService.class).toProvider(Providers.of(appProviderInst));
bind(ApplicationManagementService.class).to(ApplicationManagementServiceImpl.class).in(Singleton.class);
bind(ApplicationStatusUpdateService.class).to(ApplicationStatusUpdateServiceImpl.class).in(Singleton.class);
bind(ApplicationHealthCheckService.class).to(ApplicationHealthCheckServiceImpl.class).in(Singleton.class);
}
}
ModuleRegistry
public static ModuleRegistry load(Module... context) {
LOGGER.warn("Loading application extension modules");
ModuleRegistry registry = new ModuleRegistryImpl();
Guice.createInjector(context).getInstance(ApplicationProviderService.class).getProviders().forEach((provider) -> {
LOGGER.warn("Registering modules from {}", provider);
provider.register(registry);
});
return registry;
}
b)EntityRepositoryScanner注册所有的Entity
个人理解这个Entity可能指的是所有组件?
final Collection<Class<? extends TaggedLogAPIEntity>> entityClasses = repo.getEntitySet();
for (Class<? extends TaggedLogAPIEntity> clazz : entityClasses) {
EntityDefinitionManager.registerEntity(clazz);
EntityRepository repo
public synchronized Collection<Class<? extends TaggedLogAPIEntity>> getEntitySet()
{ return new ArrayList<Class<? extends TaggedLogAPIEntity>>(entitySet);
}
EntityDefinitionManager.registerEntity
public static void registerEntity(Class<? extends TaggedLogAPIEntity> clazz) throws IllegalArgumentException{
registerEntity(createEntityDefinition(clazz));
}
public static EntityDefinition createEntityDefinition(Class<? extends TaggedLogAPIEntity> cls) {
final EntityDefinition ed = new EntityDefinition();
ed.setEntityClass(cls);
// parse cls' annotations
Table table = cls.getAnnotation(Table.class);
if(table == null || table.value().isEmpty()){
throw new IllegalArgumentException("Entity class must have a non-empty table name annotated with @Table");
}
String tableName = table.value();
if(EagleConfigFactory.load().isTableNamePrefixedWithEnvironment()){
tableName = EagleConfigFactory.load().getEnv() + "_" + tableName;
}
ed.setTable(tableName);
ColumnFamily family = cls.getAnnotation(ColumnFamily.class);
if(family == null || family.value().isEmpty()){
throw new IllegalArgumentException("Entity class must have a non-empty column family name annotated with @ColumnFamily");
}
ed.setColumnFamily(family.value());
Prefix prefix = cls.getAnnotation(Prefix.class);
if(prefix == null || prefix.value().isEmpty()){
throw new IllegalArgumentException("Entity class must have a non-empty prefix name annotated with @Prefix");
}
ed.setPrefix(prefix.value());
TimeSeries ts = cls.getAnnotation(TimeSeries.class);
if(ts == null){
throw new IllegalArgumentException("Entity class must have a non-empty timeseries name annotated with @TimeSeries");
}
ed.setTimeSeries(ts.value());
Service service = cls.getAnnotation(Service.class);
if(service == null || service.value().isEmpty()){
ed.setService(cls.getSimpleName());
} else {
ed.setService(service.value());
}
Metric m = cls.getAnnotation(Metric.class);
Map<String, Class<?>> dynamicFieldTypes = new HashMap<String, Class<?>>();
if(m != null){
// metric has to be timeseries
if(!ts.value()){
throw new IllegalArgumentException("Metric entity must be time series as well");
}
MetricDefinition md = new MetricDefinition();
md.setInterval(m.interval());
ed.setMetricDefinition(md);
}
java.lang.reflect.Field[] fields = cls.getDeclaredFields();
for(java.lang.reflect.Field f : fields){
Column column = f.getAnnotation(Column.class);
if(column == null || column.value().isEmpty()){
continue;
}
Class<?> fldCls = f.getType();
// intrusive check field type for metric entity
checkFieldTypeForMetric(ed.getMetricDefinition(), f.getName(), fldCls, dynamicFieldTypes);
Qualifier q = new Qualifier();
q.setDisplayName(f.getName());
q.setQualifierName(column.value());
EntitySerDeser<?> serDeser = _serDeserMap.get(fldCls);
if(serDeser == null){
// throw new IllegalArgumentException(fldCls.getName() + " in field " + f.getName() +
// " of entity " + cls.getSimpleName() + " has no serializer associated ");
serDeser = DefaultJavaObjctSerDeser.INSTANCE;
}
q.setSerDeser((EntitySerDeser<Object>)serDeser);
ed.getQualifierNameMap().put(q.getQualifierName(), q);
ed.getDisplayNameMap().put(q.getDisplayName(), q);
// TODO: should refine rules, consider fields like "hCol", getter method should be gethCol() according to org.apache.commons.beanutils.PropertyUtils
final String propertyName = f.getName().substring(0,1).toUpperCase() + f.getName().substring(1);
String getterName = "get" + propertyName;
try {
Method method = cls.getMethod(getterName);
ed.getQualifierGetterMap().put(f.getName(), method);
} catch (Exception e) {
// Check if the type is boolean
getterName = "is" + propertyName;
try {
Method method = cls.getMethod(getterName);
ed.getQualifierGetterMap().put(f.getName(), method);
} catch (Exception e1) {
throw new IllegalArgumentException("Field " + f.getName() + " hasn't defined valid getter method: " + getterName, e);
}
}
if(LOG.isDebugEnabled()) LOG.debug("Field registered " + q);
}
// TODO: Lazy create because not used at all
// dynamically create bean class
if(ed.getMetricDefinition() != null){
Class<?> metricCls = createDynamicClassForMetric(cls.getName()+"_SingleTimestamp", dynamicFieldTypes);
ed.getMetricDefinition().setSingleTimestampEntityClass(metricCls);
}
final Partition partition = cls.getAnnotation(Partition.class);
if (partition != null) {
final String[] partitions = partition.value();
ed.setPartitions(partitions);
// Check if partition fields are all tag fields. Partition field can't be column field, must be tag field.
for (String part : partitions) {
if (!ed.isTag(part)) {
throw new IllegalArgumentException("Partition field can't be column field, must be tag field. "
+ "Partition name: " + part);
}
}
}
final Indexes indexes = cls.getAnnotation(Indexes.class);
if (indexes != null) {
final Index[] inds = indexes.value();
final IndexDefinition[] indexDefinitions = new IndexDefinition[inds.length];
for (int i = 0; i < inds.length; ++i) {
final Index ind = inds[i];
indexDefinitions[i] = new IndexDefinition(ed, ind);
}
ed.setIndexes(indexDefinitions);
}
final ServicePath path = cls.getAnnotation(ServicePath.class);
if (path != null) {
if (path.path() != null && (!path.path().isEmpty())) {
ed.setServiceCreationPath(path.path());
}
}
final Tags tags = cls.getAnnotation(Tags.class);
if(tags != null) {
String[] tagNames = tags.value();
ed.setTags(tagNames);
}
return ed;
}
2)run函数
public void run(ServerConfig configuration, Environment environment) throws Exception {
environment.getApplicationContext().setContextPath(ServerConfig.getContextPath());
environment.jersey().register(RESTExceptionMapper.class);
environment.jersey().setUrlPattern(ServerConfig.getApiBasePath());
environment.getObjectMapper().setFilters(TaggedLogAPIEntity.getFilterProvider());
environment.getObjectMapper().registerModule(new EntityJsonModule());
// Automatically scan all REST resources
new PackagesResourceConfig(ServerConfig.getResourcePackage()).getClasses().forEach(environment.jersey()::register);
// Swagger resources
environment.jersey().register(ApiListingResource.class);
BeanConfig swaggerConfig = new BeanConfig();
swaggerConfig.setTitle(ServerConfig.getServerName());
swaggerConfig.setVersion(ServerConfig.getServerVersion().version);
swaggerConfig.setBasePath(ServerConfig.getApiBasePath());
swaggerConfig.setResourcePackage(ServerConfig.getResourcePackage());
swaggerConfig.setLicense(ServerConfig.getLicense());
swaggerConfig.setLicenseUrl(ServerConfig.getLicenseUrl());
swaggerConfig.setDescription(Version.str());
swaggerConfig.setScan(true);
// Simple CORS filter
environment.servlets().addFilter(SimpleCORSFiler.class.getName(), new SimpleCORSFiler())
.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
// Register authentication provider
BasicAuthBuilder authBuilder = new BasicAuthBuilder(configuration.getAuthConfig(), environment);
environment.jersey().register(authBuilder.getBasicAuthProvider());
if (configuration.getAuthConfig().isEnabled()) {
environment.jersey().getResourceConfig().getResourceFilterFactories()
.add(new BasicAuthResourceFilterFactory(authBuilder.getBasicAuthenticator()));
}
registerAppServices(environment);
}
jersey().register注册REST接口对应的resources
// Automatically scan all REST resources
new PackagesResourceConfig(ServerConfig.getResourcePackage()).getClasses().forEach(environment.jersey()::register);
getResourcePackage()返回"org.apache.eagle"。
个人理解是在org.apache.eagle包下的所有Resource类都被注册。
PackagesResourceConfig是ResourceConfig的子类。(https://www.cnblogs.com/newstar/archive/2013/06/01/3112086.html)
jersey 的使用,必须要有一个全局的配置类,这个类需满足以下条件:
1、@ApplicationPath 注解该类
2、并且在参数中指定相对路径继承org.glassfish.jersey.server.ResourceConfig 类
3、该类构造方法中设置jersey的配置,比如指定接口的包路径
@ApplicationPath("/")
public class RESTServiceConfig extends ResourceConfig {
public RESTServiceConfig() {
packages("web.rest");
register(MultiPartFeature.class);
}
}
(https://www.jianshu.com/p/15c32cb52da1)