All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.yx.bean.Booter Maven / Gradle / Ivy
/**
* Copyright (C) 2016 - 2030 youtongluan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.yx.bean;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import org.slf4j.Logger;
import org.yx.annotation.spec.InjectSpec;
import org.yx.annotation.spec.Specs;
import org.yx.bean.watcher.BeanCreateWatcher;
import org.yx.bean.watcher.BeanInjectWatcher;
import org.yx.bean.watcher.BootWatcher;
import org.yx.common.matcher.BooleanMatcher;
import org.yx.common.matcher.Matchers;
import org.yx.common.scaner.ClassScaner;
import org.yx.conf.AppInfo;
import org.yx.exception.SimpleSumkException;
import org.yx.log.Logs;
import org.yx.main.StartConstants;
import org.yx.main.StartContext;
import org.yx.main.SumkServer;
import org.yx.util.CollectionUtil;
import org.yx.util.kit.PriorityKits;
public final class Booter {
private final Logger logger = Logs.ioc();
private final Predicate excludeMatcher;
private final BeanFieldFinder fieldFinder;
private final List watchers = new ArrayList<>();
public Booter() {
this.excludeMatcher = createExcludeMatcher();
logger.debug("bean exclude matcher:{}", excludeMatcher);
this.fieldFinder = StartContext.inst().get(BeanFieldFinder.class, new DefaultBeanFieldFinder());
}
public Predicate excludeMatcher() {
return this.excludeMatcher;
}
private Predicate createExcludeMatcher() {
final String name = "sumk.ioc.exclude";
List list = new ArrayList<>(AppInfo.subMap(name + ".").values());
String exclude = AppInfo.get(name, null);
if (exclude != null) {
list.add(exclude);
}
if (list.isEmpty()) {
return BooleanMatcher.FALSE;
}
StringBuilder sb = new StringBuilder();
for (String v : list) {
sb.append(v).append(Matchers.SPLIT);
}
return Matchers.createWildcardMatcher(sb.toString(), 2);
}
public void start(List packageNames) throws Exception {
packageNames = rehandle(packageNames);
Predicate optional = this.createOptional();
List> orignClazzList = this.loadClasses(packageNames, optional);
this.publish(orignClazzList, optional);
this.autoWiredAll();
new PluginBooter().start();
Runtime.getRuntime().addShutdownHook(new Thread(SumkServer::stop));
}
private List> unmodifyClassList(List> list) {
return CollectionUtil.unmodifyList(list.toArray(new Class[list.size()]));
}
private void publish(List> clazzList, Predicate optional) throws Exception {
watchers.sort(null);
clazzList = unmodifyClassList(clazzList);
for (BootWatcher b : this.watchers) {
List> temp = b.publish(clazzList, optional);
if (temp != null) {
clazzList = unmodifyClassList(temp);
}
}
}
private List rehandle(List packageNames) {
if (packageNames.isEmpty()) {
logger.warn("property [sumk.ioc] is empty");
}
packageNames = new ArrayList<>(packageNames);
if (!packageNames.contains(StartConstants.INNER_PACKAGE)) {
packageNames.add(StartConstants.INNER_PACKAGE);
}
return packageNames;
}
@SuppressWarnings("unchecked")
private Predicate createOptional() {
Object obj = StartContext.inst().get("sumk.bean.scan.option");
if (obj instanceof Predicate) {
return (Predicate) obj;
}
return Matchers.createWildcardMatcher(AppInfo.get("sumk.ioc.optional"));
}
private List> loadClasses(List packageNames, Predicate optional) throws Exception {
Collection clzs = ClassScaner.listClasses(packageNames);
List> clazzList = new ArrayList<>(clzs.size());
Predicate excludeBooter = Matchers.createWildcardMatcher("sumk.ioc.booter.exclude", 1);
for (String c : clzs) {
if (excludeMatcher.test(c)) {
logger.info("{} excluded", c);
continue;
}
try {
if (logger.isTraceEnabled()) {
logger.trace("{} begin loading", c);
}
Class clz = Loader.loadClassExactly(c);
if ((clz.getModifiers() & (Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC
| Modifier.INTERFACE)) != Modifier.PUBLIC || clz.isAnonymousClass() || clz.isLocalClass()
|| clz.isAnnotation() || clz.isEnum()) {
continue;
}
clazzList.add(clz);
if (BootWatcher.class.isAssignableFrom(clz) && !excludeBooter.test(clz.getName())) {
BootWatcher b = (BootWatcher) Loader.newInstance(clz);
watchers.add(b);
}
} catch (LinkageError e) {
if (c.startsWith("org.yx.") || optional.test(c)) {
logger.debug("{} ignored because: {}", c, e.getMessage());
continue;
}
logger.error("{}加载失败,原因是:{}", c, e.getLocalizedMessage());
throw e;
}
}
clazzList = PriorityKits.sort(clazzList);
if (clazzList.size() > 5 && logger.isDebugEnabled()) {
logger.debug("scan class size:{}, {} {}..{} {}", clazzList.size(), clazzList.get(0).getSimpleName(),
clazzList.get(1).getSimpleName(), clazzList.get(clazzList.size() - 2).getSimpleName(),
clazzList.get(clazzList.size() - 1).getSimpleName());
logger.trace("ordered class:\n{}", clazzList);
}
return clazzList;
}
private void injectField(Field f, Object bean, Object target) throws IllegalAccessException {
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(bean, target);
}
private void autoWiredAll() throws Exception {
List beans = CollectionUtil.unmodifyList(InnerIOC.beans().toArray());
logger.trace("after beans create...");
for (BeanCreateWatcher w : IOC.getBeans(BeanCreateWatcher.class)) {
w.afterCreate(beans);
}
logger.trace("inject beans properties...");
beans = CollectionUtil.unmodifyList(InnerIOC.beans().toArray());
for (Object bean : beans) {
injectProperties(bean);
}
logger.trace("after beans installed...");
for (BeanInjectWatcher watcher : IOC.getBeans(BeanInjectWatcher.class)) {
watcher.afterInject(beans);
}
logger.trace("plugins starting...");
}
private void injectProperties(Object bean) throws Exception {
Class tempClz = bean.getClass();
while (tempClz != null && (!tempClz.getName().startsWith(Loader.JAVA_PRE))) {
Field[] fs = tempClz.getDeclaredFields();
for (Field f : fs) {
InjectSpec inject = Specs.extractInject(bean, f);
if (inject == null) {
continue;
}
Object target = this.fieldFinder.findTarget(f, bean, inject);
if (target == null) {
if (inject.allowEmpty()) {
continue;
}
throw new SimpleSumkException(-235435658,
bean.getClass().getName() + "." + f.getName() + " cannot injected.");
}
injectField(f, bean, target);
}
tempClz = tempClz.getSuperclass();
}
}
}