feat:加入spring-brick和plugin-core

master
xiwa 2024-02-08 23:47:38 +08:00
parent b047655808
commit 71e74d447e
413 changed files with 38766 additions and 17 deletions

View File

@ -6,7 +6,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<artifactId>iot-common-core</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -30,6 +30,11 @@
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-message-bus</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-message-bus</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-message-bus</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>

55
iot-plugin-core/pom.xml Normal file
View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.iotkit</groupId>
<artifactId>iot-iita-core</artifactId>
<version>1.0.2</version>
</parent>
<artifactId>iot-plugin-core</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-brick.version>3.1.4</spring-brick.version>
</properties>
<dependencies>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>iot-common-core</artifactId>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>iot-script-engine</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>iot-message-core</artifactId>
</dependency>
<!--====================第三方库===================-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.gitee.starblues</groupId>
<artifactId>spring-brick</artifactId>
<version>${spring-brick.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,22 @@
package cc.iotkit.plugin.core;
import java.util.Map;
/**
*
*
* @author sjg
*/
public interface IPlugin {
/**
* mqttip
*
* @param pk key
* @param dn dn
* @return
*/
Map<String, Object> getLinkInfo(String pk, String dn);
}

View File

@ -0,0 +1,21 @@
package cc.iotkit.plugin.core;
import java.util.Map;
/**
*
*
* @author sjg
*/
public interface IPluginConfig {
/**
*
*
* @param pluginId id
* @return config
*/
Map<String, Object> getConfig(String pluginId);
}

View File

@ -0,0 +1,27 @@
package cc.iotkit.plugin.core;
import cc.iotkit.script.IScriptEngine;
/**
* 宿
*
* @author sjg
*/
public interface IPluginScript {
/**
*
*
* @param pluginId id
* @return IScriptEngine
*/
IScriptEngine getScriptEngine(String pluginId);
/**
*
*
* @param pluginId id
*/
void reloadScript(String pluginId);
}

View File

@ -0,0 +1,18 @@
package cc.iotkit.plugin.core;
import java.util.HashMap;
import java.util.Map;
/**
*
*
* @author sjg
*/
public class LocalPluginConfig implements IPluginConfig {
@Override
public Map<String, Object> getConfig(String pluginId) {
//本地的直接用程序中默认值
return new HashMap<>(0);
}
}

View File

@ -0,0 +1,50 @@
package cc.iotkit.plugin.core;
import cc.iotkit.common.utils.StringUtils;
import cc.iotkit.common.utils.file.FileUtils;
import cc.iotkit.script.IScriptEngine;
import cc.iotkit.script.ScriptEngineFactory;
import java.net.URL;
import java.nio.charset.Charset;
/**
*
*
* @author sjg
*/
public class LocalPluginScript implements IPluginScript {
private IScriptEngine scriptEngine;
public LocalPluginScript(String scriptPath) {
if (StringUtils.isBlank(scriptPath)) {
return;
}
URL resource = LocalPluginScript.class.getClassLoader().getResource(scriptPath);
if (resource == null) {
return;
}
String script = FileUtils.readString(resource.getFile(), Charset.defaultCharset());
initScriptEngine(script);
}
public IScriptEngine initScriptEngine(String script) {
if (StringUtils.isBlank(script)) {
return null;
}
scriptEngine = ScriptEngineFactory.getJsEngine(script);
return scriptEngine;
}
@Override
public IScriptEngine getScriptEngine(String pluginId) {
return scriptEngine;
}
@Override
public void reloadScript(String pluginId) {
}
}

View File

@ -0,0 +1,49 @@
package cc.iotkit.plugin.core.thing;
import cc.iotkit.plugin.core.thing.actions.ActionResult;
import cc.iotkit.plugin.core.thing.actions.down.DeviceConfig;
import cc.iotkit.plugin.core.thing.actions.down.PropertyGet;
import cc.iotkit.plugin.core.thing.actions.down.PropertySet;
import cc.iotkit.plugin.core.thing.actions.down.ServiceInvoke;
/**
*
*
* @author sjg
*/
public interface IDevice {
/**
*
*
* @param action
* @return result
*/
ActionResult config(DeviceConfig action);
/**
*
*
* @param action
* @return result
*/
ActionResult propertyGet(PropertyGet action);
/**
*
*
* @param action
* @return result
*/
ActionResult propertySet(PropertySet action);
/**
*
*
* @param action
* @return result
*/
ActionResult serviceInvoke(ServiceInvoke action);
}

View File

@ -0,0 +1,49 @@
package cc.iotkit.plugin.core.thing;
import cc.iotkit.plugin.core.thing.actions.ActionResult;
import cc.iotkit.plugin.core.thing.actions.IDeviceAction;
import cc.iotkit.plugin.core.thing.model.ThingDevice;
import cc.iotkit.plugin.core.thing.model.ThingProduct;
import java.util.Map;
/**
*
*
* @author sjg
*/
public interface IThingService {
/**
*
*
* @param action IDeviceAction
* @return result
*/
ActionResult post(String pluginId, IDeviceAction action);
/**
*
*
* @param pk key
* @return Product
*/
ThingProduct getProduct(String pk);
/**
*
*
* @param deviceName dn
* @return DeviceInfo
*/
ThingDevice getDevice(String deviceName);
/**
*
*
* @param deviceName dn
* @return
*/
Map<String, ?> getProperty(String deviceName);
}

View File

@ -0,0 +1,31 @@
package cc.iotkit.plugin.core.thing.actions;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
/**
* @author sjg
*/
@Data
@SuperBuilder
@ToString(callSuper = true)
public abstract class AbstractAction implements IDeviceAction {
protected String id;
protected ActionType type;
protected String productKey;
protected String deviceName;
protected Long time;
public AbstractAction() {
}
public AbstractAction(ActionType type) {
this.type = type;
}
}

View File

@ -0,0 +1,29 @@
package cc.iotkit.plugin.core.thing.actions;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
*
* @author sjg
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ActionResult {
/**
* 0:x:
*/
private int code;
/**
*
*/
private String reason;
}

View File

@ -0,0 +1,39 @@
package cc.iotkit.plugin.core.thing.actions;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*
* @author sjg
*/
@Getter
@AllArgsConstructor
public enum ActionType {
//注册
REGISTER("register"),
//设备拓扑更新
TOPOLOGY("topology"),
//在离线状态变更
STATE_CHANGE("state_change"),
//属性上报
PROPERTY_REPORT("property_report"),
//事件上报
EVENT_REPORT("event_report"),
//服务回复
SERVICE_REPLY("service_reply"),
//属性设置
PROPERTY_SET("property_set"),
//属性获取
PROPERTY_GET("property_get"),
//服务调用
SERVICE_INVOKE("service_invoke"),
//配置
CONFIG("config");
private final String type;
}

View File

@ -0,0 +1,21 @@
package cc.iotkit.plugin.core.thing.actions;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
* @author sjg
*/
@Getter
@AllArgsConstructor
public enum DeviceState {
//在线
ONLINE("online"),
//离线
OFFLINE("offline");
private final String state;
}

View File

@ -0,0 +1,24 @@
package cc.iotkit.plugin.core.thing.actions;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*
* @author sjg
*/
@Getter
@AllArgsConstructor
public enum EventLevel {
//信息
INFO("info"),
//告警
WARN("warn"),
//错误
ERROR("error");
private final String type;
}

View File

@ -0,0 +1,79 @@
package cc.iotkit.plugin.core.thing.actions;
/**
*
*
* @author sjg
*/
public interface IDeviceAction {
/**
* id
*
* @return id
*/
String getId();
/**
* id
*
* @param id id
*/
void setId(String id);
/**
*
*
* @return ActionType
*/
ActionType getType();
/**
*
*
* @param type type
*/
void setType(ActionType type);
/**
* key
*
* @return ProductKey
*/
String getProductKey();
/**
* key
*
* @param productKey pk
*/
void setProductKey(String productKey);
/**
* DN
*
* @return DN
*/
String getDeviceName();
/**
* DN
*
* @param deviceName dn
*/
void setDeviceName(String deviceName);
/**
*
*
* @return timespan
*/
Long getTime();
/**
*
*
* @param time timestamp
*/
void setTime(Long time);
}

View File

@ -0,0 +1,40 @@
package cc.iotkit.plugin.core.thing.actions.down;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.Map;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class DeviceConfig extends AbstractAction {
/**
*
*/
private String module;
/**
*
*/
private Map<String, Object> config;
@Override
public ActionType getType() {
return ActionType.CONFIG;
}
}

View File

@ -0,0 +1,35 @@
package cc.iotkit.plugin.core.thing.actions.down;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class PropertyGet extends AbstractAction {
/**
*
*/
private List<String> keys;
@Override
public ActionType getType() {
return ActionType.PROPERTY_GET;
}
}

View File

@ -0,0 +1,35 @@
package cc.iotkit.plugin.core.thing.actions.down;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.Map;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class PropertySet extends AbstractAction {
/**
*
*/
private Map<String, ?> params;
@Override
public ActionType getType() {
return ActionType.PROPERTY_SET;
}
}

View File

@ -0,0 +1,45 @@
package cc.iotkit.plugin.core.thing.actions.down;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.Map;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class ServiceInvoke extends AbstractAction {
/**
*
*/
private String name;
/**
*
*/
private Map<String, ?> params;
/**
*
*/
private Map<String, ?> config;
@Override
public ActionType getType() {
return ActionType.SERVICE_INVOKE;
}
}

View File

@ -0,0 +1,36 @@
package cc.iotkit.plugin.core.thing.actions.up;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.*;
import lombok.experimental.SuperBuilder;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@ToString(callSuper = true)
public class DeviceRegister extends AbstractAction {
/**
*
*/
private String model;
/**
*
*/
private String version;
@Override
public ActionType getType() {
return ActionType.REGISTER;
}
}

View File

@ -0,0 +1,29 @@
package cc.iotkit.plugin.core.thing.actions.up;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import cc.iotkit.plugin.core.thing.actions.DeviceState;
import lombok.*;
import lombok.experimental.SuperBuilder;
/**
* 线
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@ToString(callSuper = true)
public class DeviceStateChange extends AbstractAction {
private DeviceState state;
@Override
public ActionType getType() {
return ActionType.STATE_CHANGE;
}
}

View File

@ -0,0 +1,33 @@
package cc.iotkit.plugin.core.thing.actions.up;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.util.List;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@ToString(callSuper = true)
public class DeviceTopology extends AbstractAction {
/**
*
*/
private List<String> subDevices;
@Override
public ActionType getType() {
return ActionType.TOPOLOGY;
}
}

View File

@ -0,0 +1,44 @@
package cc.iotkit.plugin.core.thing.actions.up;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import cc.iotkit.plugin.core.thing.actions.EventLevel;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.util.Map;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@ToString(callSuper = true)
public class EventReport extends AbstractAction {
/**
*
*/
private String name;
/**
*
*/
private EventLevel level;
/**
*
*/
private Map<String, Object> params;
@Override
public ActionType getType() {
return ActionType.EVENT_REPORT;
}
}

View File

@ -0,0 +1,33 @@
package cc.iotkit.plugin.core.thing.actions.up;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.util.Map;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@ToString(callSuper = true)
public class PropertyReport extends AbstractAction {
/**
*
*/
private Map<String, Object> params;
@Override
public ActionType getType() {
return ActionType.PROPERTY_REPORT;
}
}

View File

@ -0,0 +1,48 @@
package cc.iotkit.plugin.core.thing.actions.up;
import cc.iotkit.plugin.core.thing.actions.AbstractAction;
import cc.iotkit.plugin.core.thing.actions.ActionType;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.util.Map;
/**
*
*
* @author sjg
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@ToString(callSuper = true)
public class ServiceReply extends AbstractAction {
/**
*
*/
private String name;
/**
* id
*/
private String replyId;
/**
* ,0:,x:
*/
private int code;
/**
*
*/
private Map<String, Object> params;
@Override
public ActionType getType() {
return ActionType.SERVICE_REPLY;
}
}

View File

@ -0,0 +1,40 @@
package cc.iotkit.plugin.core.thing.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
*
* @author sjg
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ThingDevice {
private String deviceId;
/**
* key
*/
private String productKey;
/**
* dn
*/
private String deviceName;
/**
*
*/
private String model;
/**
*
*/
private String secret;
}

View File

@ -0,0 +1,29 @@
package cc.iotkit.plugin.core.thing.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
*
* @author sjg
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ThingProduct {
private String productKey;
private String productSecret;
private String name;
private String category;
private Integer nodeType;
}

View File

@ -6,7 +6,7 @@
<parent>
<artifactId>iot-iita-core</artifactId>
<groupId>cc.iotkit</groupId>
<version>1.0.1</version>
<version>1.0.2</version>
</parent>
<artifactId>iot-script-engine</artifactId>

98
iot-spring-brick/pom.xml Normal file
View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.iotkit</groupId>
<artifactId>iot-iita-core</artifactId>
<version>1.0.2</version>
</parent>
<groupId>com.gitee.starblues</groupId>
<artifactId>iot-spring-brick</artifactId>
<packaging>pom</packaging>
<version>3.1.4</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>spring-brick-common</module>
<module>spring-brick-loader</module>
<module>spring-brick</module>
<module>spring-brick-bootstrap</module>
<module>spring-brick-maven-packager</module>
</modules>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://gitee.com/starblues/springboot-plugin-framework-parent</url>
<connection>scm:https://gitee.com/starblues/springboot-plugin-framework-parent.git</connection>
<developerConnection>scm:https://gitee.com/starblues/springboot-plugin-framework-parent.git</developerConnection>
<tag>1.0</tag>
</scm>
<developers>
<developer>
<name>StarBlues</name>
<email>starblues@foxmail.com</email>
<url>https://gitee.com/starblues/</url>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<plugin.skip>true</plugin.skip>
</properties>
</profile>
<profile>
<id>release</id>
<properties>
<plugin.skip>false</plugin.skip>
</properties>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.gitee.starblues</groupId>
<artifactId>iot-spring-brick</artifactId>
<version>3.1.4</version>
</parent>
<artifactId>spring-brick-bootstrap</artifactId>
<packaging>jar</packaging>
<description>插件启动引导模块</description>
<properties>
<javax.servlet-api.version>4.0.1</javax.servlet-api.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.gitee.starblues</groupId>
<artifactId>spring-brick</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,58 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.bootstrap.realize.AutowiredTypeDefiner;
import com.gitee.starblues.utils.ObjectUtils;
import java.util.*;
/**
* ClassDefiner
*
* @author starBlues
* @since 3.0.3
* @version 3.0.3
*/
public class AutowiredTypeDefinerConfig {
private final Set<AutowiredTypeDefiner.ClassDefiner> classDefiners;
public AutowiredTypeDefinerConfig(){
this.classDefiners = new HashSet<>();
}
Set<AutowiredTypeDefiner.ClassDefiner> getClassDefiners(){
return classDefiners;
}
public AutowiredTypeDefinerConfig add(AutowiredType.Type type, String... classNamePatterns){
if(type != null && classNamePatterns != null && classNamePatterns.length > 0){
classDefiners.add(AutowiredTypeDefiner.ClassDefiner.config(type, classNamePatterns));
}
return this;
}
public AutowiredTypeDefinerConfig add(AutowiredType.Type type, Class<?>... classes){
if(type != null && classes != null && classes.length > 0){
classDefiners.add(AutowiredTypeDefiner.ClassDefiner.config(type, classes));
}
return this;
}
}

View File

@ -0,0 +1,47 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.realize.AutowiredTypeDefiner;
import com.gitee.starblues.utils.ObjectUtils;
import com.gitee.starblues.utils.UrlUtils;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import java.util.Collections;
import java.util.Set;
/**
*
*
* @author starBlues
* @since 3.0.3
* @version 3.1.0
*/
public interface AutowiredTypeResolver {
/**
* descriptor
* @param descriptor descriptor
* @return AutowiredType.Type
*/
AutowiredType.Type resolve(DependencyDescriptor descriptor);
}

View File

@ -0,0 +1,150 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.core.descriptor.InsidePluginDescriptor;
import com.gitee.starblues.integration.AutoIntegrationConfiguration;
import com.gitee.starblues.integration.IntegrationConfiguration;
import com.gitee.starblues.loader.launcher.DevelopmentModeSetting;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.LiveBeansView;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.1.2
*/
public class ConfigurePluginEnvironment {
private final Logger logger = LoggerFactory.getLogger(ConfigurePluginEnvironment.class);
private final static String PLUGIN_PROPERTY_NAME = "pluginPropertySources";
private final static String SPRING_CONFIG_NAME = "spring.config.name";
private final static String SPRING_CONFIG_LOCATION = "spring.config.location";
private final static String SPRING_JMX_UNIQUE_NAMES = "spring.jmx.unique-names";
private final static String SPRING_ADMIM_ENABLED = "spring.application.admin.enabled";
private final static String SPRING_ADMIN_JMX_NAME = "spring.application.admin.jmx-name";
private final static String SPRING_ADMIN_JMX_VALUE = "org.springframework.boot:type=Admin,name=";
public static final String REGISTER_SHUTDOWN_HOOK_PROPERTY = "logging.register-shutdown-hook";
public static final String MBEAN_DOMAIN_PROPERTY_NAME = "spring.liveBeansView.mbeanDomain";
private final ProcessorContext processorContext;
private final InsidePluginDescriptor pluginDescriptor;
public ConfigurePluginEnvironment(ProcessorContext processorContext) {
this.processorContext = Assert.isNotNull(processorContext, "processorContext 不能为空");
this.pluginDescriptor = Assert.isNotNull(processorContext.getPluginDescriptor(),
"pluginDescriptor 不能为空");
}
public void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
Map<String, Object> env = new HashMap<>();
String pluginId = pluginDescriptor.getPluginId();
String configFileName = pluginDescriptor.getConfigFileName();
if(!ObjectUtils.isEmpty(configFileName)){
env.put(SPRING_CONFIG_NAME, PluginFileUtils.getFileName(configFileName));
}
String configFileLocation = pluginDescriptor.getConfigFileLocation();
if(!ObjectUtils.isEmpty(configFileLocation)){
env.put(SPRING_CONFIG_LOCATION, getConfigFileLocation(configFileLocation));
}
env.put(AutoIntegrationConfiguration.ENABLE_STARTER_KEY, false);
env.put(SPRING_JMX_UNIQUE_NAMES, true);
// 直接禁用插件的 spring-admin mbean
env.put(SPRING_ADMIM_ENABLED, false);
env.put(SPRING_ADMIN_JMX_NAME, SPRING_ADMIN_JMX_VALUE + pluginId);
env.put(REGISTER_SHUTDOWN_HOOK_PROPERTY, false);
env.put(MBEAN_DOMAIN_PROPERTY_NAME, pluginId);
try{
// fix: https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I57965
// 优先注册LiveBeansView对象防止注册异常
Method method = LiveBeansView.class.getDeclaredMethod("registerApplicationContext", ConfigurableApplicationContext.class);
method.setAccessible(true);
method.invoke(null,processorContext.getApplicationContext());
} catch (Exception ex){
logger.error("LiveBeansView.registerApplicationContext失败. {}", ex.getMessage(), ex);
}
if(DevelopmentModeSetting.coexist()){
env.put(AutoIntegrationConfiguration.ENABLE_STARTER_KEY, false);
}
configProfiles(environment);
environment.getPropertySources().addFirst(new MapPropertySource(PLUGIN_PROPERTY_NAME, env));
}
public void logProfiles(ConfigurableEnvironment environment){
IntegrationConfiguration configuration = processorContext.getConfiguration();
String fromMainMsg = configuration.pluginFollowProfile() ? " from main" : " ";
String[] activeProfiles = environment.getActiveProfiles();
if(activeProfiles.length > 0){
logger.info("Plugin[{}] following profiles are active{}: {}",
MsgUtils.getPluginUnique(pluginDescriptor),
fromMainMsg,
StringUtils.toStrByArray(activeProfiles));
} else {
logger.info("Plugin[{}] No active profile set, falling back to default profiles{}: {}",
MsgUtils.getPluginUnique(pluginDescriptor),
fromMainMsg,
StringUtils.toStrByArray(environment.getDefaultProfiles()));
}
}
private void configProfiles(ConfigurableEnvironment environment){
IntegrationConfiguration configuration = processorContext.getConfiguration();
if(!configuration.pluginFollowProfile()){
return;
}
MainApplicationContext mainApplicationContext = processorContext.getMainApplicationContext();
String[] mainActiveProfiles = mainApplicationContext.getActiveProfiles();
if(mainActiveProfiles.length > 0){
environment.setActiveProfiles(mainActiveProfiles);
} else {
logger.info("Plugin[{}] No active profile set, falling back to default profiles: {}",
MsgUtils.getPluginUnique(pluginDescriptor),
StringUtils.toStrByArray(environment.getDefaultProfiles()));
}
}
private String getConfigFileLocation(String configFileLocation){
String path = FilesUtils.resolveRelativePath(new File("").getAbsolutePath(), configFileLocation);
// 拼接最后字符斜杠
if(path.endsWith(FilesUtils.SLASH) || path.endsWith(File.separator)){
return path;
} else {
return path + File.separator;
}
}
}

View File

@ -0,0 +1,76 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.realize.AutowiredTypeDefiner;
import com.gitee.starblues.utils.UrlUtils;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import java.util.Collections;
import java.util.Set;
/**
* AutowiredTypeResolver
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
public class DefaultAutowiredTypeResolver implements AutowiredTypeResolver{
private final Set<AutowiredTypeDefiner.ClassDefiner> classDefiners;
private final PathMatcher pathMatcher = new AntPathMatcher();
public DefaultAutowiredTypeResolver(ProcessorContext processorContext) {
AutowiredTypeDefiner autowiredTypeDefiner = processorContext.getSpringPluginBootstrap().autowiredTypeDefiner();
if(autowiredTypeDefiner != null){
AutowiredTypeDefinerConfig definerConfig = new AutowiredTypeDefinerConfig();
autowiredTypeDefiner.config(definerConfig);
classDefiners = definerConfig.getClassDefiners();
} else {
classDefiners = Collections.emptySet();
}
}
@Override
public AutowiredType.Type resolve(DependencyDescriptor descriptor){
String name = descriptor.getDependencyType().getName();
String classNamePath = UrlUtils.formatMatchUrl(name);
for (AutowiredTypeDefiner.ClassDefiner classDefiner : classDefiners) {
Set<String> classNamePatterns = classDefiner.getClassNamePatterns();
for (String classNamePattern : classNamePatterns) {
if(pathMatcher.match(classNamePattern, classNamePath)){
return classDefiner.getAutowiredType();
}
}
}
AutowiredType autowiredType = descriptor.getAnnotation(AutowiredType.class);
if(autowiredType != null){
return autowiredType.value();
} else {
return AutowiredType.Type.PLUGIN;
}
}
}

View File

@ -0,0 +1,120 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.bootstrap.realize.PluginCloseListener;
import com.gitee.starblues.bootstrap.realize.StopValidator;
import com.gitee.starblues.bootstrap.utils.DestroyUtils;
import com.gitee.starblues.bootstrap.utils.SpringBeanUtils;
import com.gitee.starblues.core.PluginCloseType;
import com.gitee.starblues.core.exception.PluginProhibitStopException;
import com.gitee.starblues.spring.ApplicationContext;
import com.gitee.starblues.spring.ApplicationContextProxy;
import com.gitee.starblues.spring.SpringPluginHook;
import com.gitee.starblues.spring.WebConfig;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;
import java.util.List;
import java.util.Map;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.1.0
*/
public class DefaultSpringPluginHook implements SpringPluginHook {
protected final SpringPluginProcessor pluginProcessor;
protected final ProcessorContext processorContext;
private final StopValidator stopValidator;
public DefaultSpringPluginHook(SpringPluginProcessor pluginProcessor,
ProcessorContext processorContext) {
this.pluginProcessor = pluginProcessor;
this.processorContext = processorContext;
this.stopValidator = SpringBeanUtils.getExistBean(processorContext.getApplicationContext(),
StopValidator.class);
}
/**
*
*/
@Override
public void stopVerify() {
if(stopValidator == null){
return;
}
try {
StopValidator.Result result = stopValidator.verify();
if(result != null && !result.isVerify()){
throw new PluginProhibitStopException(processorContext.getPluginDescriptor(),
result.getMessage());
}
} catch (Exception e){
throw new PluginProhibitStopException(processorContext.getPluginDescriptor(),
e.getMessage());
}
}
@Override
public void close(PluginCloseType closeType) throws Exception{
try {
GenericApplicationContext applicationContext = processorContext.getApplicationContext();
callPluginCloseListener(applicationContext, closeType);
pluginProcessor.close(processorContext);
applicationContext.close();
processorContext.clearRegistryInfo();
DestroyUtils.destroyAll(null, SpringFactoriesLoader.class, "cache", Map.class);
} catch (Exception e){
e.printStackTrace();
} finally {
SpringPluginBootstrapBinder.remove();
}
}
@Override
public ApplicationContext getApplicationContext() {
return new ApplicationContextProxy(processorContext.getApplicationContext().getBeanFactory());
}
@Override
public WebConfig getWebConfig() {
return processorContext.getWebConfig();
}
private void callPluginCloseListener(GenericApplicationContext applicationContext, PluginCloseType closeType){
List<PluginCloseListener> pluginCloseListeners = SpringBeanUtils.getBeans(
applicationContext, PluginCloseListener.class);
if(pluginCloseListeners.isEmpty()){
return;
}
for (PluginCloseListener pluginCloseListener : pluginCloseListeners) {
try {
pluginCloseListener.close(applicationContext, processorContext.getPluginInfo(), closeType);
} catch (Exception e){
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,106 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.SpringBeanFactory;
import com.gitee.starblues.spring.environment.EmptyEnvironmentProvider;
import com.gitee.starblues.spring.environment.EnvironmentProvider;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* MainApplicationContext
*
* @author starBlues
* @since 3.0.0
* @version 3.1.1
*/
public class EmptyMainApplicationContext implements MainApplicationContext {
private final SpringBeanFactory springBeanFactory = new EmptySpringBeanFactory();
@Override
public SpringBeanFactory getSpringBeanFactory() {
return springBeanFactory;
}
@Override
public Object getSourceBeanFactory() {
return null;
}
@Override
public void close() throws Exception {
}
@Override
public Map<String, Map<String, Object>> getConfigurableEnvironment() {
return Collections.emptyMap();
}
@Override
public EnvironmentProvider getEnvironmentProvider() {
return new EmptyEnvironmentProvider();
}
@Override
public String[] getActiveProfiles() {
return new String[0];
}
@Override
public String[] getDefaultProfiles() {
return new String[0];
}
@Override
public Object resolveDependency(String requestingBeanName, Class<?> dependencyType) {
return null;
}
@Override
public boolean isWebEnvironment() {
return false;
}
@Override
public Object getSourceApplicationContext() {
return null;
}
@Override
public boolean isRegisterController() {
return false;
}
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return null;
}
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return null;
}
}

View File

@ -0,0 +1,185 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.spring.SpringBeanFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.core.ResolvableType;
import java.lang.annotation.Annotation;
import java.util.Map;
/**
* SpringBeanFactory
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class EmptySpringBeanFactory implements SpringBeanFactory {
@Override
public boolean containsBeanDefinition(String beanName) {
return false;
}
@Override
public int getBeanDefinitionCount() {
return 0;
}
@Override
public String[] getBeanDefinitionNames() {
return new String[0];
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
return null;
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
return null;
}
@Override
public String[] getBeanNamesForType(ResolvableType type) {
return new String[0];
}
@Override
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
return new String[0];
}
@Override
public String[] getBeanNamesForType(Class<?> type) {
return new String[0];
}
@Override
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
return new String[0];
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return null;
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
return null;
}
@Override
public String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType) {
return new String[0];
}
@Override
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException {
return null;
}
@Override
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException {
return null;
}
@Override
public <A extends Annotation> A findAnnotationOnBean(String s, Class<A> aClass, boolean b) throws NoSuchBeanDefinitionException {
return null;
}
@Override
public Object getBean(String name) throws BeansException {
return null;
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return null;
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return null;
}
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return null;
}
@Override
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
return null;
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) {
return null;
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
return null;
}
@Override
public boolean containsBean(String name) {
return false;
}
@Override
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException {
return false;
}
@Override
public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return null;
}
@Override
public Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
return null;
}
@Override
public String[] getAliases(String name) {
return new String[0];
}
}

View File

@ -0,0 +1,63 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.core.descriptor.PluginDescriptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* ApplicationContext
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
public class PluginApplicationContext extends AnnotationConfigApplicationContext {
private final PluginDescriptor pluginDescriptor;
public PluginApplicationContext(DefaultListableBeanFactory beanFactory,
ProcessorContext processorContext) {
super(beanFactory);
setResourceLoader(processorContext.getResourceLoader());
this.pluginDescriptor = processorContext.getPluginDescriptor();
}
@Override
public void registerShutdownHook() {
// 忽略
}
@Override
public String getApplicationName() {
return pluginDescriptor.getPluginId();
}
@Override
public void refresh() throws BeansException, IllegalStateException {
super.refresh();
}
@Override
public void close() {
super.close();
}
}

View File

@ -0,0 +1,122 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.core.descriptor.InsidePluginDescriptor;
import com.gitee.starblues.integration.IntegrationConfiguration;
import com.gitee.starblues.spring.SpringBeanFactory;
import com.gitee.starblues.spring.environment.EnvironmentProvider;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
public abstract class PluginContextHolder {
private static volatile Boolean INITIALIZED = false;
private static ProcessorContext processorContext;
private static ClassLoader pluginClassLoader;
private static InsidePluginDescriptor pluginDescriptor;
private static IntegrationConfiguration configuration;
private static Boolean mainIsWebEnv;
private static SpringBeanFactory mainSpringBeanFactory;
private PluginContextHolder(){}
static void initialize(ProcessorContext processorContext){
if(INITIALIZED){
return;
}
PluginContextHolder.processorContext = processorContext;
PluginContextHolder.pluginClassLoader = processorContext.getClassLoader();
PluginContextHolder.pluginDescriptor = processorContext.getPluginDescriptor();
PluginContextHolder.configuration = processorContext.getConfiguration();
PluginContextHolder.mainIsWebEnv = processorContext.getMainApplicationContext().isWebEnvironment();
PluginContextHolder.mainSpringBeanFactory = processorContext.getMainBeanFactory();
INITIALIZED = true;
}
/**
*
* @return EnvironmentProvider
*/
public static EnvironmentProvider getEnvironmentProvider(){
check();
return processorContext.getMainApplicationContext().getEnvironmentProvider();
}
/**
*
* @return IntegrationConfiguration
*/
public static IntegrationConfiguration getConfiguration() {
check();
return configuration;
}
/**
* SpringBeanFactory . Bean
* @return SpringBeanFactory
*/
public static SpringBeanFactory getMainSpringBeanFactory() {
check();
return mainSpringBeanFactory;
}
/**
* web
* @return Boolean
*/
public static Boolean getMainIsWebEnv() {
check();
return mainIsWebEnv;
}
/**
* classloader
* @return ClassLoader
*/
public static ClassLoader getPluginClassLoader() {
check();
return pluginClassLoader;
}
/**
*
* @return InsidePluginDescriptor
*/
public static InsidePluginDescriptor getPluginDescriptor() {
check();
return pluginDescriptor;
}
private static void check(){
if(!INITIALIZED){
throw new IllegalStateException("PluginContextHolder 未初始化");
}
}
}

View File

@ -0,0 +1,146 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.coexist.CoexistAllowAutoConfiguration;
import com.gitee.starblues.common.PluginDisableAutoConfig;
import com.gitee.starblues.loader.launcher.DevelopmentModeSetting;
import com.gitee.starblues.utils.ObjectUtils;
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
import java.util.*;
/**
* AutoConfiguration
*
* @author starBlues
* @version 3.1.0
* @since 3.0.3
*/
public class PluginDisableAutoConfiguration implements AutoConfigurationImportFilter {
private static final ThreadLocal<Boolean> LAUNCH_PLUGIN = new ThreadLocal<Boolean>();
public PluginDisableAutoConfiguration(){
}
public static void setLaunchPlugin() {
LAUNCH_PLUGIN.set(true);
}
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
if(DevelopmentModeSetting.isolation()){
return new IsolationDisableAutoConfiguration().match(autoConfigurationClasses, autoConfigurationMetadata);
} else if(DevelopmentModeSetting.coexist()){
return new CoexistDisableAutoConfiguration().match(autoConfigurationClasses, autoConfigurationMetadata);
} else {
boolean[] permitAll = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < autoConfigurationClasses.length; i++) {
permitAll[i] = permit(
PluginDisableAutoConfig.getCommonPluginDisableAutoConfig(),
autoConfigurationClasses[i]);
}
return permitAll;
}
}
private static boolean permit(Collection<String> disableCollection, String className){
if(ObjectUtils.isEmpty(className)){
return true;
}
for (String disableFuzzyClass : disableCollection) {
if (className.contains(disableFuzzyClass)) {
return false;
}
}
return true;
}
private static class IsolationDisableAutoConfiguration implements AutoConfigurationImportFilter{
private final List<String> disableFuzzyClass = new ArrayList<>();
IsolationDisableAutoConfiguration(){
addDisableFuzzyClasses();
}
private void addDisableFuzzyClasses() {
disableFuzzyClass.add("org.springframework.boot.autoconfigure.http");
disableFuzzyClass.add("org.springframework.boot.autoconfigure.web");
disableFuzzyClass.add("org.springframework.boot.autoconfigure.websocket");
disableFuzzyClass.add("org.springframework.boot.autoconfigure.jackson");
disableFuzzyClass.add("org.springframework.boot.autoconfigure.webservices");
disableFuzzyClass.addAll(PluginDisableAutoConfig.getCommonPluginDisableAutoConfig());
}
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
boolean[] match = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < autoConfigurationClasses.length; i++) {
String autoConfigurationClass = autoConfigurationClasses[i];
if(autoConfigurationClass == null || "".equals(autoConfigurationClass)){
continue;
}
match[i] = permit(disableFuzzyClass, autoConfigurationClass);
}
return match;
}
}
private static class CoexistDisableAutoConfiguration implements AutoConfigurationImportFilter{
public CoexistDisableAutoConfiguration(){
}
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
Boolean launchPlugin = LAUNCH_PLUGIN.get();
boolean[] match = new boolean[autoConfigurationClasses.length];
try {
if(launchPlugin != null && launchPlugin){
CoexistAllowAutoConfiguration configuration = SpringPluginBootstrapBinder.get()
.getCoexistAllowAutoConfiguration();
for (int i = 0; i < autoConfigurationClasses.length; i++) {
String autoConfigurationClass = autoConfigurationClasses[i];
if(ObjectUtils.isEmpty(autoConfigurationClass)){
continue;
}
if(permit(PluginDisableAutoConfig.getCommonPluginDisableAutoConfig(), autoConfigurationClass)){
match[i] = configuration.match(autoConfigurationClass);
} else {
match[i] = false;
}
}
return match;
} else {
for (int i = 0; i < autoConfigurationClasses.length; i++) {
match[i] = true;
}
}
return match;
} finally {
LAUNCH_PLUGIN.remove();
}
}
}
}

View File

@ -0,0 +1,364 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.utils.DestroyUtils;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.SpringBeanFactory;
import com.gitee.starblues.utils.ReflectionUtils;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.lang.Nullable;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* BeanFactory
*
* @author starBlues
* @since 3.0.3
* @version 3.0.3
*/
public class PluginListableBeanFactory extends DefaultListableBeanFactory {
private static final Logger LOG = LoggerFactory.getLogger(PluginListableBeanFactory.class);
private final MainApplicationContext applicationContext;
@Setter
private AutowiredTypeResolver autowiredTypeResolver;
public PluginListableBeanFactory(ProcessorContext processorContext) {
this.applicationContext = processorContext.getMainApplicationContext();
this.autowiredTypeResolver = getAutowiredTypeResolver(processorContext);
}
protected AutowiredTypeResolver getAutowiredTypeResolver(ProcessorContext processorContext){
return new DefaultAutowiredTypeResolver(processorContext);
}
@SuppressWarnings("unchecked")
@Override
public Object resolveDependency(DependencyDescriptor descriptor,
@Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames,
@Nullable TypeConverter typeConverter) throws BeansException {
AutowiredType.Type autowiredType = getAutowiredType(descriptor);
Class<?> dependencyType = descriptor.getDependencyType();
if (dependencyType == ObjectFactory.class || dependencyType == ObjectProvider.class) {
Object dependencyObj = super.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames,
typeConverter);
ObjectProvider<Object> provider = (ObjectProvider<Object>) dependencyObj;
return new PluginObjectProviderWrapper(provider, requestingBeanName, descriptor, autowiredType);
}
if(autowiredType == AutowiredType.Type.MAIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
throw new NoSuchBeanDefinitionException(descriptor.getDependencyType());
} else if(autowiredType == AutowiredType.Type.PLUGIN){
return super.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
} else if(autowiredType == AutowiredType.Type.PLUGIN_MAIN){
try {
return super.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames,
typeConverter);
} catch (BeansException e){
if(e instanceof NoSuchBeanDefinitionException){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
}
throw e;
}
} else if(autowiredType == AutowiredType.Type.MAIN_PLUGIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj instanceof ObjectProvider){
ObjectProvider<Object> provider = (ObjectProvider<Object>) dependencyObj;
return new PluginObjectProviderWrapper(provider, requestingBeanName, descriptor, autowiredType);
}
if(dependencyObj != null){
return dependencyObj;
}
return super.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames,
typeConverter);
}
throw new NoSuchBeanDefinitionException(descriptor.getDependencyType());
}
@Override
public void destroySingletons() {
String[] beanDefinitionNames = getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
destroyBean(beanDefinitionName);
}
super.destroySingletons();
destroyAll();
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
return super.getBeanProvider(requiredType, allowEagerInit);
}
protected AutowiredType.Type getAutowiredType(DependencyDescriptor descriptor){
return autowiredTypeResolver.resolve(descriptor);
}
protected Object resolveDependencyFromMain(String requestingBeanName, DependencyDescriptor descriptor){
Object dependencyObj = null;
try {
dependencyObj = applicationContext.resolveDependency(requestingBeanName,
descriptor.getDependencyType());
} catch (Exception e){
return null;
}
return dependencyObj;
}
private void destroyAll(){
ReflectionUtils.findField(this.getClass(), field -> {
field.setAccessible(true);
try {
Object o = field.get(this);
DestroyUtils.destroyAll(o);
} catch (IllegalAccessException e) {
// 忽略
}
return false;
});
}
private class PluginObjectProviderWrapper implements ObjectProvider<Object> {
private final ObjectProvider<Object> pluginObjectProvider;
private final String requestingBeanName;
private final DependencyDescriptor descriptor;
private final AutowiredType.Type autowiredType;
private PluginObjectProviderWrapper(ObjectProvider<Object> pluginObjectProvider,
String requestingBeanName,
DependencyDescriptor descriptor,
AutowiredType.Type autowiredType) {
this.pluginObjectProvider = pluginObjectProvider;
this.requestingBeanName = requestingBeanName;
this.descriptor = new NestedDependencyDescriptor(descriptor);
this.autowiredType = autowiredType;
}
@Override
public Object getObject() throws BeansException {
if(autowiredType == AutowiredType.Type.PLUGIN) {
return pluginObjectProvider.getObject();
} else if(autowiredType == AutowiredType.Type.MAIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
} else if(autowiredType == AutowiredType.Type.PLUGIN_MAIN) {
try {
return pluginObjectProvider.getObject();
} catch (Exception e) {
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if (dependencyObj != null) {
return dependencyObj;
}
throw e;
}
} else if(autowiredType == AutowiredType.Type.MAIN_PLUGIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
return pluginObjectProvider.getObject();
}
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
@Override
public Object getObject(final Object... args) throws BeansException {
if(autowiredType == AutowiredType.Type.PLUGIN){
return pluginObjectProvider.getObject(args);
} else if(autowiredType == AutowiredType.Type.MAIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
} else if(autowiredType == AutowiredType.Type.PLUGIN_MAIN){
try {
return pluginObjectProvider.getObject();
} catch (Exception e){
try {
return applicationContext.getSpringBeanFactory().getBean(requestingBeanName, args);
} catch (Exception e2){
// 忽略
}
throw e;
}
} else if(autowiredType == AutowiredType.Type.MAIN_PLUGIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
return pluginObjectProvider.getObject(args);
}
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
@Override
@Nullable
public Object getIfAvailable() throws BeansException {
if(autowiredType == AutowiredType.Type.PLUGIN){
return pluginObjectProvider.getIfAvailable();
} else if(autowiredType == AutowiredType.Type.MAIN){
return resolveDependencyFromMain(requestingBeanName, descriptor);
} else if(autowiredType == AutowiredType.Type.PLUGIN_MAIN){
Object dependencyObj = pluginObjectProvider.getIfAvailable();
if(dependencyObj == null){
dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
}
return dependencyObj;
} else if(autowiredType == AutowiredType.Type.MAIN_PLUGIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
return pluginObjectProvider.getIfAvailable();
}
return null;
}
@Override
public void ifAvailable(Consumer<Object> dependencyConsumer) throws BeansException {
Object ifAvailable = getIfAvailable();
if(ifAvailable != null){
dependencyConsumer.accept(ifAvailable);
}
}
@Override
@Nullable
public Object getIfUnique() throws BeansException {
if(autowiredType == AutowiredType.Type.PLUGIN){
return pluginObjectProvider.getIfUnique();
} else if(autowiredType == AutowiredType.Type.MAIN){
return resolveDependencyFromMain(requestingBeanName, descriptor);
} else if(autowiredType == AutowiredType.Type.PLUGIN_MAIN){
Object dependencyObj = pluginObjectProvider.getIfUnique();
if(dependencyObj == null){
dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
}
return dependencyObj;
} else if(autowiredType == AutowiredType.Type.MAIN_PLUGIN){
Object dependencyObj = resolveDependencyFromMain(requestingBeanName, descriptor);
if(dependencyObj != null){
return dependencyObj;
}
return pluginObjectProvider.getIfUnique();
}
return null;
}
@Override
public void ifUnique(Consumer<Object> dependencyConsumer) throws BeansException {
Object ifUnique = getIfUnique();
if(ifUnique != null){
dependencyConsumer.accept(ifUnique);
}
}
@Override
public Stream<Object> stream() {
if(autowiredType == AutowiredType.Type.PLUGIN){
return pluginObjectProvider.stream();
} else if(autowiredType == AutowiredType.Type.MAIN){
return getStreamOfMain().stream();
} else if (autowiredType == AutowiredType.Type.PLUGIN_MAIN){
Stream<Object> stream = pluginObjectProvider.stream();
List<Object> collect = stream.collect(Collectors.toList());
if(!collect.isEmpty()){
return collect.stream();
}
return getStreamOfMain().stream();
} else if(autowiredType == AutowiredType.Type.MAIN_PLUGIN){
Set<Object> collection = getStreamOfMain();
if(!collection.isEmpty()){
return collection.stream();
}
return pluginObjectProvider.stream();
}
return Stream.empty();
}
@Override
public Stream<Object> orderedStream() {
if(autowiredType == AutowiredType.Type.PLUGIN){
return pluginObjectProvider.orderedStream();
} else if(autowiredType == AutowiredType.Type.MAIN){
return getStreamOfMain().stream().sorted();
} else if(autowiredType == AutowiredType.Type.PLUGIN_MAIN){
Stream<Object> stream = pluginObjectProvider.stream();
List<Object> collect = stream.collect(Collectors.toList());
if(!collect.isEmpty()){
return collect.stream();
}
return getStreamOfMain().stream().sorted();
} else if(autowiredType == AutowiredType.Type.MAIN_PLUGIN){
Set<Object> collection = getStreamOfMain();
if(!collection.isEmpty()){
return collection.stream().sorted();
}
return pluginObjectProvider.stream();
}
return Stream.empty();
}
@SuppressWarnings("unchecked")
private Set<Object> getStreamOfMain(){
SpringBeanFactory springBeanFactory = applicationContext.getSpringBeanFactory();
Map<String, ?> beansOfType = springBeanFactory.getBeansOfType(descriptor.getDependencyType());
return new HashSet<>(beansOfType.values());
}
}
private static class NestedDependencyDescriptor extends DependencyDescriptor {
public NestedDependencyDescriptor(DependencyDescriptor original) {
super(original);
increaseNestingLevel();
}
}
}

View File

@ -0,0 +1,107 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.common.PackageStructure;
import com.gitee.starblues.core.DefaultPluginInsideInfo;
import com.gitee.starblues.core.PluginInsideInfo;
import com.gitee.starblues.core.descriptor.DevPluginDescriptorLoader;
import com.gitee.starblues.core.descriptor.InsidePluginDescriptor;
import com.gitee.starblues.core.descriptor.PluginDescriptorLoader;
import com.gitee.starblues.core.descriptor.decrypt.EmptyPluginDescriptorDecrypt;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.integration.AutoIntegrationConfiguration;
import com.gitee.starblues.integration.IntegrationConfiguration;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.extract.DefaultOpExtractFactory;
import com.gitee.starblues.spring.extract.OpExtractFactory;
import com.gitee.starblues.spring.invoke.DefaultInvokeSupperCache;
import com.gitee.starblues.spring.invoke.InvokeSupperCache;
import com.gitee.starblues.utils.FilesUtils;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Interactive
*
* @author starBlues
* @since 3.0.0
* @version 3.1.0
*/
public class PluginOneselfInteractive implements PluginInteractive {
private final PluginInsideInfo pluginInsideInfo;
private final MainApplicationContext mainApplicationContext;
private final IntegrationConfiguration configuration;
private final InvokeSupperCache invokeSupperCache;
private final OpExtractFactory opExtractFactory;
public PluginOneselfInteractive(){
this.pluginInsideInfo = createPluginInsideInfo();
this.mainApplicationContext = new EmptyMainApplicationContext();
this.configuration = new AutoIntegrationConfiguration();
this.invokeSupperCache = new DefaultInvokeSupperCache();
this.opExtractFactory = new DefaultOpExtractFactory();
}
@Override
public InsidePluginDescriptor getPluginDescriptor() {
return pluginInsideInfo.getPluginDescriptor();
}
@Override
public PluginInsideInfo getPluginInsideInfo() {
return pluginInsideInfo;
}
@Override
public MainApplicationContext getMainApplicationContext() {
return mainApplicationContext;
}
@Override
public IntegrationConfiguration getConfiguration() {
return configuration;
}
@Override
public InvokeSupperCache getInvokeSupperCache() {
return invokeSupperCache;
}
@Override
public OpExtractFactory getOpExtractFactory() {
return opExtractFactory;
}
private PluginInsideInfo createPluginInsideInfo(){
EmptyPluginDescriptorDecrypt descriptorDecrypt = new EmptyPluginDescriptorDecrypt();
try (PluginDescriptorLoader pluginDescriptorLoader = new DevPluginDescriptorLoader(descriptorDecrypt)){
Path classesPath = Paths.get(this.getClass().getResource("/").toURI()).getParent();
String metaInf = FilesUtils.joiningFilePath(classesPath.toString(), PackageStructure.META_INF_NAME);
InsidePluginDescriptor pluginDescriptor = pluginDescriptorLoader.load(Paths.get(metaInf));
if(pluginDescriptor == null){
throw new RuntimeException("没有发现插件信息, 请使用框架提供的Maven插件器对插件进行编译!");
}
return new DefaultPluginInsideInfo(pluginDescriptor);
} catch (Exception e){
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,86 @@
package com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.bootstrap.processor.oneself.ConfigureMainPluginEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* SpringApplication
*
* @author starBlues
* @version 3.1.0
* @since 3.0.4
*/
public class PluginOneselfSpringApplication extends SpringApplication {
private final Logger logger = LoggerFactory.getLogger(PluginSpringApplication.class);
protected final SpringPluginProcessor pluginProcessor;
protected final ProcessorContext processorContext;
private final ConfigurePluginEnvironment configurePluginEnvironment;
private final GenericApplicationContext applicationContext;
public PluginOneselfSpringApplication(SpringPluginProcessor pluginProcessor,
ProcessorContext processorContext,
Class<?>... primarySources) {
super(primarySources);
this.pluginProcessor = pluginProcessor;
this.processorContext = processorContext;
this.configurePluginEnvironment = new ConfigurePluginEnvironment(processorContext);
this.applicationContext = getApplicationContext();
}
protected GenericApplicationContext getApplicationContext() {
return (GenericApplicationContext) super.createApplicationContext();
}
@Override
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
super.configureEnvironment(environment, args);
configurePluginEnvironment.configureEnvironment(environment, args);
new ConfigureMainPluginEnvironment(processorContext).configureEnvironment(environment, args);
}
@Override
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
super.bindToSpringApplication(environment);
configurePluginEnvironment.logProfiles(environment);
}
@Override
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContext;
}
@Override
public ConfigurableApplicationContext run(String... args) {
try {
processorContext.setApplicationContext(this.applicationContext);
PluginContextHolder.initialize(processorContext);
pluginProcessor.initialize(processorContext);
return super.run(args);
} catch (Exception e) {
pluginProcessor.failure(processorContext);
logger.debug("启动插件[{}]失败. {}",
processorContext.getPluginDescriptor().getPluginId(),
e.getMessage(), e);
throw new RuntimeException(e);
}
}
@Override
protected void refresh(ConfigurableApplicationContext applicationContext) {
pluginProcessor.refreshBefore(processorContext);
super.refresh(applicationContext);
pluginProcessor.refreshAfter(processorContext);
}
}

View File

@ -0,0 +1,126 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ResourceLoader;
/**
* SpringApplication
*
* @author starBlues
* @since 3.0.0
* @version 3.1.0
*/
public class PluginSpringApplication extends SpringApplication {
private final Logger logger = LoggerFactory.getLogger(PluginSpringApplication.class);
protected final SpringPluginProcessor pluginProcessor;
protected final ProcessorContext processorContext;
private final ConfigurePluginEnvironment configurePluginEnvironment;
private final GenericApplicationContext applicationContext;
private final ResourceLoader resourceLoader;
public PluginSpringApplication(SpringPluginProcessor pluginProcessor,
ProcessorContext processorContext,
Class<?>... primarySources) {
super(primarySources);
this.pluginProcessor = pluginProcessor;
this.processorContext = processorContext;
this.resourceLoader = processorContext.getResourceLoader();
this.configurePluginEnvironment = new ConfigurePluginEnvironment(processorContext);
this.applicationContext = getApplicationContext();
setDefaultPluginConfig();
}
protected GenericApplicationContext getApplicationContext(){
DefaultListableBeanFactory beanFactory = getBeanFactory(processorContext);
if(processorContext.getMainApplicationContext().isWebEnvironment()){
return new PluginWebApplicationContext(beanFactory, processorContext);
} else {
return new PluginApplicationContext(beanFactory, processorContext);
}
}
protected DefaultListableBeanFactory getBeanFactory(ProcessorContext processorContext){
return new PluginListableBeanFactory(processorContext);
}
public void setDefaultPluginConfig(){
setResourceLoader(resourceLoader);
setBannerMode(Banner.Mode.OFF);
setEnvironment(new StandardEnvironment());
setWebApplicationType(WebApplicationType.NONE);
setRegisterShutdownHook(false);
setLogStartupInfo(false);
}
@Override
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
super.configureEnvironment(environment, args);
configurePluginEnvironment.configureEnvironment(environment, args);
}
@Override
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
super.bindToSpringApplication(environment);
configurePluginEnvironment.logProfiles(environment);
}
@Override
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContext;
}
@Override
public ConfigurableApplicationContext run(String... args) {
try {
processorContext.setApplicationContext(this.applicationContext);
PluginContextHolder.initialize(processorContext);
pluginProcessor.initialize(processorContext);
return super.run(args);
} catch (Exception e) {
pluginProcessor.failure(processorContext);
logger.debug("启动插件[{}]失败. {}",
processorContext.getPluginDescriptor().getPluginId(),
e.getMessage(), e);
throw new RuntimeException(e);
}
}
@Override
protected void refresh(ConfigurableApplicationContext applicationContext) {
pluginProcessor.refreshBefore(processorContext);
super.refresh(applicationContext);
pluginProcessor.refreshAfter(processorContext);
}
}

View File

@ -0,0 +1,95 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.listener.PluginApplicationWebEventListener;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.spring.environment.EnvironmentProvider;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerException;
/**
* web ApplicationContext
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
public class PluginWebApplicationContext extends PluginApplicationContext implements WebServerApplicationContext {
private final WebServer webServer;
private final String serverNamespace;
public PluginWebApplicationContext(DefaultListableBeanFactory beanFactory, ProcessorContext processorContext) {
super(beanFactory, processorContext);
this.webServer = new PluginSimulationWebServer(processorContext);
this.serverNamespace = processorContext.getPluginDescriptor().getPluginId();
addApplicationListener(new PluginApplicationWebEventListener(this));
}
@Override
public WebServer getWebServer() {
return webServer;
}
@Override
public String getServerNamespace() {
return serverNamespace;
}
public static class PluginSimulationWebServer implements WebServer {
private final int port;
public PluginSimulationWebServer(ProcessorContext processorContext) {
EnvironmentProvider provider = processorContext.getMainApplicationContext().getEnvironmentProvider();
Integer port = provider.getInteger("server.port");
if(port == null){
this.port = -1;
} else {
this.port = port;
}
}
@Override
public void start() throws WebServerException {
throw new InvalidWebServerException();
}
@Override
public void stop() throws WebServerException {
throw new InvalidWebServerException();
}
@Override
public int getPort() {
return port;
}
}
public static class InvalidWebServerException extends WebServerException{
public InvalidWebServerException() {
super("Invalid operation", null);
}
}
}

View File

@ -0,0 +1,42 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
import java.util.stream.Collectors;
/**
* resolve config HttpMessageConverters bean
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
public class ResolveHttpMessageConvertersConfiguration {
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,122 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap;
import com.gitee.starblues.bootstrap.coexist.CoexistAllowAutoConfiguration;
import com.gitee.starblues.bootstrap.launcher.*;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.bootstrap.realize.AutowiredTypeDefiner;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.spring.SpringPluginHook;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
public abstract class SpringPluginBootstrap {
@Getter
private ProcessorContext.RunMode runMode = ProcessorContext.RunMode.ONESELF;
@Getter
private volatile PluginInteractive pluginInteractive;
@Getter
private final List<SpringPluginProcessor> customPluginProcessors = new ArrayList<>();
@Getter
private final CoexistAllowAutoConfiguration coexistAllowAutoConfiguration = new CoexistAllowAutoConfiguration();
private final BootstrapLauncherFactory launcherFactory = new DefaultBootstrapLauncherFactory();
public SpringPluginBootstrap() {
SpringPluginBootstrapBinder.set(this);
}
public final SpringPluginHook run(String[] args){
return run(this.getClass(), args);
}
public final SpringPluginHook run(Class<?> primarySources, String[] args){
return run(new Class[]{ primarySources }, args);
}
public final SpringPluginHook run(Class<?>[] primarySources, String[] args){
return start(primarySources, args);
}
private SpringPluginHook start(Class<?>[] primarySources, String[] args){
configCoexistAllowAutoConfiguration(this.coexistAllowAutoConfiguration);
createPluginInteractive();
addCustomSpringPluginProcessor();
BootstrapLauncher bootstrapLauncher = launcherFactory.create(this);
return bootstrapLauncher.launch(primarySources, args);
}
public final SpringPluginBootstrap setPluginInteractive(PluginInteractive pluginInteractive) {
this.pluginInteractive = pluginInteractive;
this.runMode = ProcessorContext.RunMode.PLUGIN;
return this;
}
public final SpringPluginBootstrap addSpringPluginProcessor(SpringPluginProcessor springPluginProcessor){
if(springPluginProcessor != null){
customPluginProcessors.add(springPluginProcessor);
}
return this;
}
protected final void createPluginInteractive(){
if(pluginInteractive != null){
return;
}
createPluginInteractiveOfOneself();
}
protected final void createPluginInteractiveOfOneself(){
this.pluginInteractive = new PluginOneselfInteractive();
}
/**
* SpringPluginProcessor
*/
protected void addCustomSpringPluginProcessor(){}
/**
* AutowiredTypeDefiner
* @return AutowiredTypeDefiner
* @since 3.0.3
*/
protected AutowiredTypeDefiner autowiredTypeDefiner(){
return null;
}
/**
* Coexist spring-boot-auto-configuration
* @param configuration
*/
protected void configCoexistAllowAutoConfiguration(CoexistAllowAutoConfiguration configuration){
}
}

View File

@ -0,0 +1,28 @@
package com.gitee.starblues.bootstrap;
/**
* SpringPluginBootstrap
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
public class SpringPluginBootstrapBinder {
private final static ThreadLocal<SpringPluginBootstrap> BINDER = new ThreadLocal<>();
public static SpringPluginBootstrap get(){
return BINDER.get();
}
public static void set(SpringPluginBootstrap bootstrap){
BINDER.set(bootstrap);
}
public static void remove(){
BINDER.remove();
}
}

View File

@ -0,0 +1,48 @@
package com.gitee.starblues.bootstrap.annotation;
import java.lang.annotation.*;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutowiredType {
/**
* Bean
* @return Type
*/
Type value() default Type.PLUGIN;
enum Type{
/**
* Bean : ()
*/
PLUGIN,
/**
* Bean :
*/
MAIN,
/**
* Bean :
*/
PLUGIN_MAIN,
/**
* Bean :
*/
MAIN_PLUGIN
}
}

View File

@ -0,0 +1,33 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.annotation;
import java.lang.annotation.*;
/**
* web. , web
* controllerweb访thymeleaf
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DisablePluginWeb {
}

View File

@ -0,0 +1,40 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.annotation;
import java.lang.annotation.*;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OneselfConfig {
/**
*
* @return String[]
*/
String[] mainConfigFileName() default {};
}

View File

@ -0,0 +1,32 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.annotation;
import java.lang.annotation.*;
/**
* , 线ClassLoader
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResolveClassLoader {
}

View File

@ -0,0 +1,60 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.coexist;
import com.gitee.starblues.utils.ObjectUtils;
import java.util.HashSet;
import java.util.Set;
/**
* Coexist auto
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
public class CoexistAllowAutoConfiguration {
private final Set<String> allowPrefix = new HashSet<>();
public CoexistAllowAutoConfiguration(){
addDefault();
}
private void addDefault(){
allowPrefix.add("org.springframework.boot.autoconfigure.aop.AopAutoConfiguration");
}
public CoexistAllowAutoConfiguration add(String autoConfigurationClass){
if(ObjectUtils.isEmpty(autoConfigurationClass)){
return this;
}
allowPrefix.add(autoConfigurationClass);
return this;
}
public boolean match(String autoConfigurationClass){
for (String prefix : allowPrefix) {
if(autoConfigurationClass.startsWith(prefix)){
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,53 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.coexist;
import com.gitee.starblues.bootstrap.annotation.ResolveClassLoader;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* Coexist, ClassLoader
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
@Aspect
public class CoexistResolveClassLoaderAspect {
@Pointcut("@annotation(com.gitee.starblues.bootstrap.annotation.ResolveClassLoader)")
public void test() {
}
@Around("@annotation(resolveClassLoader)")
public Object around(ProceedingJoinPoint pjp, ResolveClassLoader resolveClassLoader) throws Throwable{
Thread thread = Thread.currentThread();
ClassLoader oldClassLoader = thread.getContextClassLoader();
try {
Object target = pjp.getTarget();
thread.setContextClassLoader(target.getClass().getClassLoader());
return pjp.proceed();
} finally {
thread.setContextClassLoader(oldClassLoader);
}
}
}

View File

@ -0,0 +1,38 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.launcher;
import com.gitee.starblues.spring.SpringPluginHook;
/**
*
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
public interface BootstrapLauncher {
/**
*
* @param primarySources
* @param args
* @return SpringPluginHook
*/
SpringPluginHook launch(Class<?>[] primarySources, String[] args);
}

View File

@ -0,0 +1,37 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.launcher;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
/**
* BootstrapLauncher
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
public interface BootstrapLauncherFactory {
/**
* BootstrapLauncher
* @param bootstrap SpringPluginBootstrap
* @return BootstrapLauncher
*/
BootstrapLauncher create(SpringPluginBootstrap bootstrap);
}

View File

@ -0,0 +1,111 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.launcher;
import com.gitee.starblues.bootstrap.*;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.bootstrap.coexist.CoexistResolveClassLoaderAspect;
import com.gitee.starblues.bootstrap.processor.DefaultProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.spring.SpringPluginHook;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Coexist
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
* @see com.gitee.starblues.loader.DevelopmentMode#COEXIST
*/
@AllArgsConstructor
public class CoexistBootstrapLauncher implements BootstrapLauncher{
private final SpringPluginBootstrap bootstrap;
private final SpringPluginProcessor pluginProcessor;
private final PluginInteractive pluginInteractive;
@Override
public SpringPluginHook launch(Class<?>[] primarySources, String[] args) {
ProcessorContext processorContext = new DefaultProcessorContext(
bootstrap.getRunMode(), bootstrap, pluginInteractive, bootstrap.getClass()
);
SpringApplication springApplication = new CoexistSpringApplication(
pluginProcessor,
processorContext,
primarySources);
springApplication.run(args);
return new DefaultSpringPluginHook(pluginProcessor, processorContext);
}
private static class CoexistSpringApplication extends PluginSpringApplication{
public CoexistSpringApplication(SpringPluginProcessor pluginProcessor, ProcessorContext processorContext, Class<?>... primarySources) {
super(pluginProcessor, processorContext, primarySources);
}
@Override
protected DefaultListableBeanFactory getBeanFactory(ProcessorContext processorContext) {
return new CoexistPluginListableBeanFactory(processorContext);
}
@Override
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
super.configureEnvironment(environment, args);
}
@Override
protected GenericApplicationContext getApplicationContext() {
PluginApplicationContext applicationContext = (PluginApplicationContext) super.getApplicationContext();
applicationContext.register(CoexistResolveClassLoaderAspect.class);
return applicationContext;
}
}
private static class CoexistPluginListableBeanFactory extends PluginListableBeanFactory{
public CoexistPluginListableBeanFactory(ProcessorContext processorContext) {
super(processorContext);
}
@Override
protected AutowiredTypeResolver getAutowiredTypeResolver(ProcessorContext processorContext) {
return new CoexistAutowiredTypeResolver();
}
}
private static class CoexistAutowiredTypeResolver implements AutowiredTypeResolver{
@Override
public AutowiredType.Type resolve(DependencyDescriptor descriptor) {
AutowiredType autowiredType = descriptor.getAnnotation(AutowiredType.class);
if(autowiredType != null){
return autowiredType.value();
} else {
return AutowiredType.Type.PLUGIN;
}
}
}
}

View File

@ -0,0 +1,55 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.launcher;
import com.gitee.starblues.bootstrap.PluginDisableAutoConfiguration;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.bootstrap.processor.ComposeSpringPluginProcessor;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.loader.launcher.DevelopmentModeSetting;
import java.util.List;
/**
* BootstrapLauncher
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
*/
public class DefaultBootstrapLauncherFactory implements BootstrapLauncherFactory{
@Override
public BootstrapLauncher create(SpringPluginBootstrap bootstrap) {
PluginDisableAutoConfiguration.setLaunchPlugin();
ProcessorContext.RunMode runMode = bootstrap.getRunMode();
List<SpringPluginProcessor> customPluginProcessors = bootstrap.getCustomPluginProcessors();
PluginInteractive pluginInteractive = bootstrap.getPluginInteractive();
SpringPluginProcessor pluginProcessor = new ComposeSpringPluginProcessor(runMode, customPluginProcessors);
BootstrapLauncher bootstrapLauncher = null;
if(DevelopmentModeSetting.isolation()){
bootstrapLauncher = new IsolationBootstrapLauncher(bootstrap, pluginProcessor, pluginInteractive);
} else if(DevelopmentModeSetting.coexist()){
bootstrapLauncher = new CoexistBootstrapLauncher(bootstrap, pluginProcessor, pluginInteractive);
} else {
bootstrapLauncher = new OneselfBootstrapLauncher(bootstrap, pluginProcessor, pluginInteractive);
}
return bootstrapLauncher;
}
}

View File

@ -0,0 +1,59 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.launcher;
import com.gitee.starblues.bootstrap.DefaultSpringPluginHook;
import com.gitee.starblues.bootstrap.PluginSpringApplication;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.bootstrap.processor.DefaultProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.spring.SpringPluginHook;
import lombok.AllArgsConstructor;
import org.springframework.boot.SpringApplication;
/**
* isolation
*
* @author starBlues
* @since 3.0.4
* @version 3.1.0
* @see com.gitee.starblues.loader.DevelopmentMode#ISOLATION
*/
@AllArgsConstructor
public class IsolationBootstrapLauncher implements BootstrapLauncher{
private final SpringPluginBootstrap bootstrap;
private final SpringPluginProcessor pluginProcessor;
private final PluginInteractive pluginInteractive;
@Override
public SpringPluginHook launch(Class<?>[] primarySources, String[] args) {
ProcessorContext.RunMode runMode = bootstrap.getRunMode();
ProcessorContext processorContext = new DefaultProcessorContext(
runMode, bootstrap, pluginInteractive, bootstrap.getClass()
);
SpringApplication springApplication = new PluginSpringApplication(
pluginProcessor,
processorContext,
primarySources);
springApplication.run(args);
return new DefaultSpringPluginHook(pluginProcessor, processorContext);
}
}

View File

@ -0,0 +1,47 @@
package com.gitee.starblues.bootstrap.launcher;
import com.gitee.starblues.bootstrap.DefaultSpringPluginHook;
import com.gitee.starblues.bootstrap.PluginOneselfSpringApplication;
import com.gitee.starblues.bootstrap.PluginSpringApplication;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.bootstrap.processor.DefaultProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.spring.SpringPluginHook;
import lombok.AllArgsConstructor;
import org.springframework.boot.SpringApplication;
/**
*
*
* @author starBlues
* @version 3.1.0
* @since 3.0.4
*/
@AllArgsConstructor
public class OneselfBootstrapLauncher implements BootstrapLauncher{
private final SpringPluginBootstrap bootstrap;
private final SpringPluginProcessor pluginProcessor;
private final PluginInteractive pluginInteractive;
@Override
public SpringPluginHook launch(Class<?>[] primarySources, String[] args) {
ProcessorContext.RunMode runMode = bootstrap.getRunMode();
ProcessorContext processorContext = new DefaultProcessorContext(
runMode, bootstrap, pluginInteractive, bootstrap.getClass()
);
SpringApplication springApplication = new PluginOneselfSpringApplication(
pluginProcessor,
processorContext,
primarySources);
springApplication.run(args);
return new DefaultSpringPluginHook(pluginProcessor, processorContext);
}
}

View File

@ -0,0 +1,83 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.listener;
import com.gitee.starblues.bootstrap.PluginWebApplicationContext;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.ResolvableType;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
public class PluginApplicationWebEventListener implements ApplicationListener<ApplicationEvent> {
private final PluginWebApplicationContext applicationContext;
public PluginApplicationWebEventListener(PluginWebApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationReadyEvent) {
callWebServerInitializedEvent();
}
}
@SuppressWarnings("all")
protected void callWebServerInitializedEvent(){
String[] beanNamesForType = applicationContext.getBeanNamesForType(ResolvableType.forClassWithGenerics(
ApplicationListener.class, WebServerInitializedEvent.class
));
PluginWebServerInitializedEvent pluginWebServerInitializedEvent =
new PluginWebServerInitializedEvent(applicationContext);
for (String beanName : beanNamesForType) {
try {
ApplicationListener<WebServerInitializedEvent> applicationListener =
(ApplicationListener<WebServerInitializedEvent>) applicationContext.getBean(beanName);
applicationListener.onApplicationEvent(pluginWebServerInitializedEvent);
} catch (Exception e){
e.printStackTrace();
}
}
}
public static class PluginWebServerInitializedEvent extends WebServerInitializedEvent{
private final PluginWebApplicationContext pluginWebApplicationContext;
protected PluginWebServerInitializedEvent(PluginWebApplicationContext pluginWebApplicationContext) {
super(pluginWebApplicationContext.getWebServer());
this.pluginWebApplicationContext = pluginWebApplicationContext;
}
@Override
public WebServerApplicationContext getApplicationContext() {
return pluginWebApplicationContext;
}
}
}

View File

@ -0,0 +1,202 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.bootstrap.annotation.DisablePluginWeb;
import com.gitee.starblues.bootstrap.processor.oneself.OneselfProcessor;
import com.gitee.starblues.bootstrap.processor.web.PluginControllerProcessor;
import com.gitee.starblues.bootstrap.processor.web.PluginInterceptorsProcessor;
import com.gitee.starblues.bootstrap.processor.web.PluginStaticResourceProcessor;
import com.gitee.starblues.bootstrap.utils.AnnotationUtils;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.utils.OrderUtils;
import com.gitee.starblues.utils.ObjectUtils;
import com.gitee.starblues.utils.OrderPriority;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.1.1
*/
public class ComposeSpringPluginProcessor implements SpringPluginProcessor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final ProcessorContext.RunMode runMode;
private List<SpringPluginProcessor> processors;
public ComposeSpringPluginProcessor(ProcessorContext.RunMode runMode) {
this(runMode, null);
}
public ComposeSpringPluginProcessor(ProcessorContext.RunMode runMode, List<SpringPluginProcessor> processors) {
this.runMode = runMode;
if(!ObjectUtils.isEmpty(processors)){
this.processors = processors;
} else {
this.processors = new ArrayList<>();
}
}
public void addSpringPluginProcessor(SpringPluginProcessor springPluginProcessor){
if(springPluginProcessor != null){
this.processors.add(springPluginProcessor);
}
}
@Override
public void initialize(ProcessorContext context) throws ProcessorException {
List<SpringPluginProcessor> processors = new ArrayList<>();
addDefaultProcessors(context, processors);
addDefaultWebEnvProcessors(context, processors);
addOneselfProcessors(context, processors);
processors.addAll(this.processors);
this.processors = processors.stream()
.filter(p->{
ProcessorContext.RunMode runMode = p.runMode();
return runMode == ProcessorContext.RunMode.ALL || runMode == this.runMode;
})
.sorted(OrderUtils.orderPriority(SpringPluginProcessor::order))
.collect(Collectors.toList());
for (SpringPluginProcessor processor : this.processors) {
try {
processor.initialize(context);
} catch (Throwable e){
processException(processor, "initialize", e, true);
}
}
}
@Override
public void refreshBefore(ProcessorContext context) throws ProcessorException {
for (SpringPluginProcessor processor : processors) {
try {
processor.refreshBefore(context);
} catch (Throwable e){
processException(processor, "refreshBefore", e, true);
}
}
}
@Override
public void refreshAfter(ProcessorContext context) throws ProcessorException {
for (SpringPluginProcessor processor : processors) {
try {
processor.refreshAfter(context);
} catch (Throwable e){
processException(processor, "refreshAfter", e, true);
}
}
}
@Override
public void failure(ProcessorContext context) throws ProcessorException {
for (SpringPluginProcessor processor : processors) {
try {
processor.failure(context);
} catch (Throwable e){
processException(processor, "failure", e, false);
}
}
}
@Override
public void close(ProcessorContext context) throws ProcessorException {
for (SpringPluginProcessor processor : processors) {
try {
processor.close(context);
} catch (Throwable e){
processException(processor, "close", e, false);
}
}
}
@Override
public OrderPriority order() {
return OrderPriority.getHighPriority();
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.ALL;
}
/**
*
* @param context ProcessorContext
* @param processors
*/
protected void addDefaultProcessors(ProcessorContext context, List<SpringPluginProcessor> processors){
processors.add(new FrameDefineBeanProcessor());
processors.add(new ExtractBeanProcessor());
processors.add(new InvokeOtherPluginProcessor());
}
/**
* web
* @param context ProcessorContext
* @param processors
*/
protected void addDefaultWebEnvProcessors(ProcessorContext context, List<SpringPluginProcessor> processors){
MainApplicationContext mainApplicationContext = context.getMainApplicationContext();
if(!mainApplicationContext.isWebEnvironment()){
// 主程序不是web类型, 则不进行注册
return;
}
SpringPluginBootstrap springPluginBootstrap = context.getSpringPluginBootstrap();
DisablePluginWeb disablePluginWeb = AnnotationUtils.findAnnotation(springPluginBootstrap.getClass(),
DisablePluginWeb.class);
if(disablePluginWeb != null){
return;
}
context.getWebConfig().setEnable(true);
if(mainApplicationContext.isRegisterController()){
processors.add(new PluginControllerProcessor());
}
processors.add(new PluginInterceptorsProcessor());
processors.add(new PluginStaticResourceProcessor());
}
/**
* Oneself
* @param context ProcessorContext
* @param processors
*/
private void addOneselfProcessors(ProcessorContext context, List<SpringPluginProcessor> processors) {
processors.add(new OneselfProcessor());
}
private void processException(SpringPluginProcessor processor, String executeType,
Throwable e, boolean isThrow) throws ProcessorException{
String error = "Processor[" + processor.getClass().getName() + "] execute[" + executeType + "] failure : "
+ e.getMessage();
logger.error(error, e);
if(isThrow){
throw new ProcessorException(error, e);
}
}
}

View File

@ -0,0 +1,150 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.core.PluginInfo;
import com.gitee.starblues.core.descriptor.InsidePluginDescriptor;
import com.gitee.starblues.core.launcher.plugin.CacheRegistryInfo;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.integration.IntegrationConfiguration;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.SpringBeanFactory;
import com.gitee.starblues.spring.WebConfig;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ClassUtils;
import java.util.Map;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class DefaultProcessorContext extends CacheRegistryInfo implements ProcessorContext{
private final RunMode runMode;
private final SpringPluginBootstrap springPluginBootstrap;
private final PluginInteractive pluginInteractive;
private final Class<? extends SpringPluginBootstrap> runnerClass;
private final MainApplicationContext mainApplicationContext;
private final ClassLoader classLoader;
private final ResourceLoader resourceLoader;
private final IntegrationConfiguration configuration;
private final WebConfig webConfig;
private GenericApplicationContext applicationContext;
public DefaultProcessorContext(RunMode runMode, SpringPluginBootstrap springPluginBootstrap,
PluginInteractive pluginInteractive, Class<? extends SpringPluginBootstrap> runnerClass) {
this.runMode = runMode;
this.springPluginBootstrap = springPluginBootstrap;
this.pluginInteractive = pluginInteractive;
this.runnerClass = runnerClass;
this.classLoader = getPluginClassLoader();
this.resourceLoader = new DefaultResourceLoader(this.classLoader);
this.mainApplicationContext = pluginInteractive.getMainApplicationContext();
this.configuration = pluginInteractive.getConfiguration();
this.webConfig = new WebConfig();
}
@Override
public RunMode runMode() {
return runMode;
}
@Override
public SpringPluginBootstrap getSpringPluginBootstrap() {
return springPluginBootstrap;
}
@Override
public InsidePluginDescriptor getPluginDescriptor() {
return pluginInteractive.getPluginDescriptor();
}
@Override
public PluginInfo getPluginInfo() {
return pluginInteractive.getPluginInsideInfo();
}
@Override
public Class<? extends SpringPluginBootstrap> getRunnerClass() {
return runnerClass;
}
@Override
public PluginInteractive getPluginInteractive() {
return pluginInteractive;
}
@Override
public MainApplicationContext getMainApplicationContext() {
return mainApplicationContext;
}
@Override
public SpringBeanFactory getMainBeanFactory() {
return mainApplicationContext.getSpringBeanFactory();
}
@Override
public IntegrationConfiguration getConfiguration() {
return configuration;
}
@Override
public GenericApplicationContext getApplicationContext() {
if(applicationContext == null){
return null;
}
return applicationContext;
}
@Override
public ClassLoader getClassLoader() {
return classLoader;
}
@Override
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
@Override
public WebConfig getWebConfig() {
return webConfig;
}
@Override
public void setApplicationContext(GenericApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
protected ClassLoader getPluginClassLoader(){
return ClassUtils.getDefaultClassLoader();
}
}

View File

@ -0,0 +1,63 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
import com.gitee.starblues.annotation.Extract;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorException;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.spring.extract.OpExtractFactory;
import com.gitee.starblues.utils.ObjectUtils;
import org.springframework.context.support.GenericApplicationContext;
import java.util.Map;
/**
* Extract Bean
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class ExtractBeanProcessor implements SpringPluginProcessor {
@Override
public void refreshAfter(ProcessorContext context) throws ProcessorException {
GenericApplicationContext applicationContext = context.getApplicationContext();
Map<String, Object> extractMap = applicationContext.getBeansWithAnnotation(Extract.class);
if(ObjectUtils.isEmpty(extractMap)){
return;
}
String pluginId = context.getPluginDescriptor().getPluginId();
OpExtractFactory opExtractFactory = context.getPluginInteractive().getOpExtractFactory();
for (Object extract : extractMap.values()) {
opExtractFactory.add(pluginId, extract);
}
}
@Override
public void close(ProcessorContext context) throws ProcessorException {
OpExtractFactory opExtractFactory = context.getPluginInteractive().getOpExtractFactory();
String pluginId = context.getPluginDescriptor().getPluginId();
opExtractFactory.remove(pluginId);
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.ALL;
}
}

View File

@ -0,0 +1,50 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
import com.gitee.starblues.core.descriptor.InsidePluginDescriptor;
import com.gitee.starblues.integration.AutoIntegrationConfiguration;
import com.gitee.starblues.integration.ExtendPointConfiguration;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
/**
* bean
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class FrameDefineBeanProcessor implements SpringPluginProcessor {
@Override
public void refreshBefore(ProcessorContext context) throws ProcessorException {
GenericApplicationContext applicationContext = context.getApplicationContext();
InsidePluginDescriptor pluginDescriptor = context.getPluginDescriptor();
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
beanFactory.registerSingleton("pluginDescriptor", pluginDescriptor.toPluginDescriptor());
beanFactory.registerSingleton("pluginInfo", context.getPluginInfo());
beanFactory.registerSingleton("mainApplicationContext", context.getMainApplicationContext());
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.ALL;
}
}

View File

@ -0,0 +1,128 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
import com.gitee.starblues.annotation.Caller;
import com.gitee.starblues.annotation.Supplier;
import com.gitee.starblues.bootstrap.processor.invoke.InvokeBeanFactory;
import com.gitee.starblues.bootstrap.processor.scanner.PluginClassPathBeanDefinitionScanner;
import com.gitee.starblues.spring.ApplicationContext;
import com.gitee.starblues.spring.ApplicationContextProxy;
import com.gitee.starblues.spring.invoke.InvokeSupperCache;
import com.gitee.starblues.spring.invoke.SupperCache;
import com.gitee.starblues.utils.ObjectUtils;
import com.gitee.starblues.utils.ScanUtils;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import java.util.Map;
import java.util.Set;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class InvokeOtherPluginProcessor implements SpringPluginProcessor {
@Override
public void refreshBefore(ProcessorContext context) throws ProcessorException {
InvokeCallerBeanDefinitionScanner scanner = new InvokeCallerBeanDefinitionScanner(context);
scanner.doScan(ScanUtils.getScanBasePackages(context.getRunnerClass()));
}
@Override
public void refreshAfter(ProcessorContext context) throws ProcessorException {
GenericApplicationContext applicationContext = context.getApplicationContext();
Map<String, Object> supplierBeans = applicationContext.getBeansWithAnnotation(Supplier.class);
String pluginId = context.getPluginDescriptor().getPluginId();
ApplicationContext applicationContextReflection = new ApplicationContextProxy(applicationContext);
InvokeSupperCache invokeSupperCache = context.getPluginInteractive().getInvokeSupperCache();
supplierBeans.forEach((k,v)->{
Supplier supplier = AnnotationUtils.findAnnotation(v.getClass(), Supplier.class);
String supperKey = k;
if(supplier != null && !ObjectUtils.isEmpty(supplier.value())){
supperKey = supplier.value();
}
invokeSupperCache.add(pluginId, new SupperCache(supperKey, k, applicationContextReflection));
});
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.ALL;
}
private static class InvokeCallerBeanDefinitionScanner extends PluginClassPathBeanDefinitionScanner {
private final ProcessorContext context;
public InvokeCallerBeanDefinitionScanner(ProcessorContext context) {
super(context, false);
setResourceLoader(context.getResourceLoader());
this.context = context;
addIncludeFilter(new AnnotationTypeFilter(Caller.class));
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> holders = super.doScan(basePackages);
ClassLoader pluginClassLoader = context.getClassLoader();
InvokeSupperCache invokeSupperCache = context.getPluginInteractive().getInvokeSupperCache();
for (BeanDefinitionHolder holder : holders) {
AbstractBeanDefinition definition = (AbstractBeanDefinition) holder.getBeanDefinition();
try {
Class<?> aClass = pluginClassLoader.loadClass(definition.getBeanClassName());
Caller caller = AnnotationUtils.findAnnotation(aClass, Caller.class);
if(caller == null){
continue;
}
// 是调用方
definition.getPropertyValues().add("callerAnnotation", caller);
definition.getPropertyValues().add("callerInterface", aClass);
definition.getPropertyValues().add("invokeSupperCache", invokeSupperCache);
definition.setBeanClass(InvokeBeanFactory.class);
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
return holders;
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}
}

View File

@ -0,0 +1,148 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.core.PluginInfo;
import com.gitee.starblues.core.descriptor.InsidePluginDescriptor;
import com.gitee.starblues.core.launcher.plugin.PluginInteractive;
import com.gitee.starblues.core.launcher.plugin.RegistryInfo;
import com.gitee.starblues.integration.IntegrationConfiguration;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.SpringBeanFactory;
import com.gitee.starblues.spring.WebConfig;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ResourceLoader;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public interface ProcessorContext extends RegistryInfo {
/**
*
* @return RunMode
*/
RunMode runMode();
/**
* -SpringPluginBootstrap
* @return SpringPluginBootstrap
*/
SpringPluginBootstrap getSpringPluginBootstrap();
/**
* PluginDescriptor
* @return PluginDescriptor
*/
InsidePluginDescriptor getPluginDescriptor();
/**
* PluginInfo
* @return PluginInfo
*/
PluginInfo getPluginInfo();
/**
* class
* @return Class
*/
Class<? extends SpringPluginBootstrap> getRunnerClass();
/**
* PluginInteractive
* @return PluginInteractive
*/
PluginInteractive getPluginInteractive();
/**
* ApplicationContext
* @return MainApplicationContext
*/
MainApplicationContext getMainApplicationContext();
/**
* SpringBeanFactory
* @return SpringBeanFactory
*/
SpringBeanFactory getMainBeanFactory();
/**
*
* @return IntegrationConfiguration
*/
IntegrationConfiguration getConfiguration();
/**
* ApplicationContext
* @return GenericApplicationContext
*/
GenericApplicationContext getApplicationContext();
/**
* ClassLoader
* @return ClassLoader
*/
ClassLoader getClassLoader();
/**
* loader
* @return ResourceLoader
*/
ResourceLoader getResourceLoader();
/**
* WebConfig
* @return WebConfig
*/
WebConfig getWebConfig();
/**
* set ApplicationContext
* @param applicationContext GenericApplicationContext
*/
void setApplicationContext(GenericApplicationContext applicationContext);
/**
*
*/
enum RunMode{
/**
*
*/
ALL,
/**
*
*/
PLUGIN,
/**
*
*/
ONESELF
}
}

View File

@ -0,0 +1,47 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class ProcessorException extends RuntimeException{
public ProcessorException() {
super();
}
public ProcessorException(String message) {
super(message);
}
public ProcessorException(String message, Throwable cause) {
super(message, cause);
}
public ProcessorException(Throwable cause) {
super(cause);
}
protected ProcessorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,93 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor;
import com.gitee.starblues.utils.Order;
import com.gitee.starblues.utils.OrderPriority;
/**
* spring plugin
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public interface SpringPluginProcessor extends Order {
/**
*
* @param context ProcessorContext
* @throws ProcessorException
*/
default void initialize(ProcessorContext context) throws ProcessorException{
}
/**
*
* @param context ProcessorContext
* @throws ProcessorException
*/
default void refreshBefore(ProcessorContext context) throws ProcessorException{
}
/**
*
* @param context ProcessorContext
* @throws ProcessorException
*/
default void refreshAfter(ProcessorContext context) throws ProcessorException{
}
/**
*
* @param context ProcessorContext
* @throws ProcessorException
*/
default void failure(ProcessorContext context) throws ProcessorException{
}
/**
*
* @param context ProcessorContext
* @throws ProcessorException
*/
default void close(ProcessorContext context) throws ProcessorException{
}
/**
*
* @return OrderPriority
*/
@Override
default OrderPriority order(){
return OrderPriority.getLowPriority();
}
/**
*
* @return RunMode
*/
ProcessorContext.RunMode runMode();
}

View File

@ -0,0 +1,35 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.interceptor;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public interface PluginInterceptorRegister {
/**
*
* @param registry
*/
void registry(PluginInterceptorRegistry registry);
}

View File

@ -0,0 +1,174 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.interceptor;
import com.gitee.starblues.utils.ObjectUtils;
import com.gitee.starblues.utils.UrlUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.handler.MappedInterceptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class PluginInterceptorRegistration {
private final HandlerInterceptor interceptor;
private final PluginInterceptorRegistry.Type type;
private final String pluginRestApiPrefix;
private final List<String> includePatterns = new ArrayList<>();
private final List<String> excludePatterns = new ArrayList<>();
@Nullable
private PathMatcher pathMatcher;
private int order = 0;
/**
* Create an {@link InterceptorRegistration} instance.
*
* @param interceptor
* @param type
* @param pluginRestApiPrefix
*/
public PluginInterceptorRegistration(HandlerInterceptor interceptor,
PluginInterceptorRegistry.Type type,
String pluginRestApiPrefix) {
this.interceptor = interceptor;
this.type = type;
String apiPrefix = null;
if(pluginRestApiPrefix.startsWith("/")){
apiPrefix = pluginRestApiPrefix;
} else {
apiPrefix = "/" + pluginRestApiPrefix;
}
if(apiPrefix.endsWith("/")){
apiPrefix = apiPrefix.substring(0, apiPrefix.lastIndexOf("/"));
}
this.pluginRestApiPrefix = apiPrefix;
}
/**
* Add URL patterns to which the registered interceptor should apply to.
* @param patterns patterns
* @return PluginInterceptorRegistration
*/
public PluginInterceptorRegistration addPathPatterns(String... patterns) {
if(type == PluginInterceptorRegistry.Type.GLOBAL){
this.includePatterns.addAll(Arrays.asList(patterns));
}
// 局部的
for (String pattern : patterns) {
if(ObjectUtils.isEmpty(pattern)){
continue;
}
this.includePatterns.add(UrlUtils.joiningUrlPath(pluginRestApiPrefix, pattern));
}
return this;
}
/**
* Add URL patterns to which the registered interceptor should not apply to.
* @param patterns patterns
* @return PluginInterceptorRegistration
*/
public PluginInterceptorRegistration excludePathPatterns(String... patterns) {
if(type == PluginInterceptorRegistry.Type.GLOBAL){
this.excludePatterns.addAll(Arrays.asList(patterns));
}
for (String pattern : patterns) {
if(ObjectUtils.isEmpty(pattern)){
continue;
}
this.excludePatterns.add(UrlUtils.joiningUrlPath(pluginRestApiPrefix, pattern));
}
return this;
}
/**
* A PathMatcher implementation to use with this interceptor. This is an optional,
* advanced property required only if using custom PathMatcher implementations
* that support mapping metadata other than the Ant path patterns supported
* by default.
* @param pathMatcher pathMatcher
* @return PluginInterceptorRegistration
*/
public PluginInterceptorRegistration pathMatcher(PathMatcher pathMatcher) {
this.pathMatcher = pathMatcher;
return this;
}
/**
* Specify an order position to be used. Default is 0.
* @param order order
* @since 5.0
* @return PluginInterceptorRegistration
*/
public PluginInterceptorRegistration order(int order){
this.order = order;
return this;
}
/**
* Return the order position to be used.
* @since 5.0
* @return int
*/
protected int getOrder() {
return this.order;
}
/**
* Build the underlying interceptor. If URL patterns are provided, the returned
* type is {@link MappedInterceptor}; otherwise {@link HandlerInterceptor}.
* @return object {@link MappedInterceptor} or {@link HandlerInterceptor}
*/
protected Object getInterceptor() {
if(type == PluginInterceptorRegistry.Type.PLUGIN){
if(this.includePatterns.isEmpty()){
this.includePatterns.add(UrlUtils.joiningUrlPath(pluginRestApiPrefix, "/**"));
}
}
if (this.includePatterns.isEmpty() && this.excludePatterns.isEmpty()) {
return this.interceptor;
}
String[] include = this.includePatterns.toArray(new String[]{});
String[] exclude = this.excludePatterns.toArray(new String[]{});
MappedInterceptor mappedInterceptor = new MappedInterceptor(include, exclude, this.interceptor);
if (this.pathMatcher != null) {
mappedInterceptor.setPathMatcher(this.pathMatcher);
}
return mappedInterceptor;
}
}

View File

@ -0,0 +1,114 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.interceptor;
import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class PluginInterceptorRegistry {
private final List<PluginInterceptorRegistration> registrations = new ArrayList<>();
private final String pluginRestApiPrefix;
public PluginInterceptorRegistry(String pluginRestApiPrefix) {
this.pluginRestApiPrefix = pluginRestApiPrefix;
}
/**
* Adds the provided {@link HandlerInterceptor}.
* @param interceptor the interceptor to add
* @param type type {@link Type}
* @return An {@link InterceptorRegistration} that allows you optionally configure the
* registered interceptor further for example adding URL patterns it should apply to.
*/
public PluginInterceptorRegistration addInterceptor(HandlerInterceptor interceptor, Type type) {
PluginInterceptorRegistration registration = new PluginInterceptorRegistration(interceptor,
type, pluginRestApiPrefix);
this.registrations.add(registration);
return registration;
}
/**
* Adds the provided {@link WebRequestInterceptor}.
* @param interceptor the interceptor to add
* @param type type {@link Type}
*
* @return An {@link InterceptorRegistration} that allows you optionally configure the
* registered interceptor further for example adding URL patterns it should apply to.
*/
public PluginInterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor, Type type) {
WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor);
PluginInterceptorRegistration registration = new PluginInterceptorRegistration(adapted, type,
pluginRestApiPrefix);
this.registrations.add(registration);
return registration;
}
/**
* Return all registered interceptors.
* @return interceptors
*/
public List<Object> getInterceptors() {
return this.registrations.stream()
.sorted(INTERCEPTOR_ORDER_COMPARATOR)
.map(PluginInterceptorRegistration::getInterceptor)
.collect(Collectors.toList());
}
private static final Comparator<Object> INTERCEPTOR_ORDER_COMPARATOR =
OrderComparator.INSTANCE.withSourceProvider(object -> {
if (object instanceof PluginInterceptorRegistration) {
return (Ordered) ((PluginInterceptorRegistration) object)::getOrder;
}
return null;
});
public enum Type{
/**
*
*/
GLOBAL,
/**
* , pluginRestPathPrefix
*/
PLUGIN
}
}

View File

@ -0,0 +1,68 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.invoke;
import com.gitee.starblues.annotation.Caller;
import com.gitee.starblues.spring.invoke.InvokeSupperCache;
import org.springframework.beans.factory.FactoryBean;
import java.lang.reflect.Proxy;
/**
* bean
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class InvokeBeanFactory<T> implements FactoryBean<T> {
private Class<T> callerInterface;
private Caller callerAnnotation;
private InvokeSupperCache invokeSupperCache;
@Override
@SuppressWarnings("unchecked")
public T getObject() throws Exception {
ClassLoader classLoader = callerInterface.getClassLoader();
Class<?>[] interfaces = new Class[]{callerInterface};
InvokeProxyHandler proxy = new InvokeProxyHandler(callerAnnotation, invokeSupperCache);
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
}
@Override
public Class<?> getObjectType() {
return callerInterface;
}
@Override
public boolean isSingleton() {
return true;
}
public void setCallerInterface(Class<T> callerInterface) {
this.callerInterface = callerInterface;
}
public void setCallerAnnotation(Caller callerAnnotation) {
this.callerAnnotation = callerAnnotation;
}
public void setInvokeSupperCache(InvokeSupperCache invokeSupperCache) {
this.invokeSupperCache = invokeSupperCache;
}
}

View File

@ -0,0 +1,212 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.invoke;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.starblues.annotation.Caller;
import com.gitee.starblues.annotation.Supplier;
import com.gitee.starblues.spring.invoke.InvokeSupperCache;
import com.gitee.starblues.utils.ObjectUtils;
import com.gitee.starblues.utils.ReflectionUtils;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class InvokeProxyHandler implements InvocationHandler {
private final Caller callerAnnotation;
private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final InvokeSupperCache invokeSupperCache;
public InvokeProxyHandler(Caller callerAnnotation, InvokeSupperCache invokeSupperCache) {
this.callerAnnotation = callerAnnotation;
this.invokeSupperCache = invokeSupperCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] callerArgs) throws Throwable {
String pluginId = callerAnnotation.pluginId();
Object supplierObject = invokeSupperCache.getSupperBean(pluginId, callerAnnotation.value());
if (supplierObject == null) {
if (ObjectUtils.isEmpty(pluginId)) {
throw new Exception("Not found '" + callerAnnotation.value() + "' supplier object");
} else {
throw new Exception("Not found '" + callerAnnotation.value() + "' supplier object in plugin '" +
pluginId + "'");
}
}
Caller.Method callerMethod = method.getAnnotation(Caller.Method.class);
if (callerArgs == null) {
callerArgs = new Object[]{};
}
if (callerMethod == null) {
return notAnnotationInvoke(method, supplierObject, callerArgs);
} else {
return annotationInvoke(method, callerMethod, supplierObject, callerArgs);
}
}
/**
*
* @param method
* @param callerMethod
* @param supplierObject
* @param callerArgs
* @return
* @throws Throwable
*/
private Object annotationInvoke(Method method, Caller.Method callerMethod,
Object supplierObject, Object[] callerArgs) throws Throwable{
String callerMethodName = callerMethod.value();
Class<?> supplierClass = supplierObject.getClass();
Method[] methods = supplierClass.getMethods();
Method supplierMethod = null;
for (Method m : methods) {
Supplier.Method supplierMethodAnnotation = m.getAnnotation(Supplier.Method.class);
if(supplierMethodAnnotation == null){
continue;
}
if(Objects.equals(supplierMethodAnnotation.value(), callerMethodName)){
supplierMethod = m;
break;
}
}
if(supplierMethod == null){
// 如果为空, 说明没有找到被调用者的注解, 则走没有注解的代理调用。
return notAnnotationInvoke(method, supplierObject, callerArgs);
}
Class<?>[] parameterTypes = supplierMethod.getParameterTypes();
if(parameterTypes.length != callerArgs.length){
// 参数不匹配
return notAnnotationInvoke(method, supplierObject, callerArgs);
}
Object[] supplierArgs = getSupplierArgs(callerArgs, supplierMethod);
Object invokeReturn = supplierMethod.invoke(supplierObject, supplierArgs);
return getReturnObject(invokeReturn, method);
}
/**
*
* @param method
* @param supplierObject
* @param callerArgs
* @return
* @throws Throwable
*/
private Object notAnnotationInvoke(Method method, Object supplierObject, Object[] callerArgs) throws Throwable{
String name = method.getName();
Class<?>[] supplierArgClasses = new Class[callerArgs.length];
ClassLoader classLoader = supplierObject.getClass().getClassLoader();
for (int i = 0; i < callerArgs.length; i++) {
Object callerArg = callerArgs[i];
try {
supplierArgClasses[i] = classLoader.loadClass(callerArg.getClass().getName());
} catch (Exception e){
supplierArgClasses[i] = callerArg.getClass();
}
}
Class<?> supplierClass = supplierObject.getClass();
Method supplierMethod = null;
try {
supplierMethod = supplierClass.getMethod(name, supplierArgClasses);
} catch (Exception e){
supplierMethod = findSupplierMethod(supplierClass, name, supplierArgClasses);
}
if(supplierMethod == null){
throw ReflectionUtils.getNoSuchMethodException(supplierClass, name, supplierArgClasses);
}
Object[] supplierArgs = getSupplierArgs(callerArgs, supplierMethod);
Object invokeReturn = supplierMethod.invoke(supplierObject, supplierArgs);
return getReturnObject(invokeReturn, method);
}
private Object[] getSupplierArgs(Object[] callerArgs, Method supplierMethod) throws Exception{
if(callerArgs == null || callerArgs.length == 0){
return new Class<?>[]{};
}
Class<?>[] supplierParameterTypes = supplierMethod.getParameterTypes();
Object[] supplierArgs = new Object[callerArgs.length];
for (int i = 0; i < supplierParameterTypes.length; i++) {
Class<?> supplierParameterType = supplierParameterTypes[i];
Object arg = callerArgs[i];
if(supplierParameterType.isAssignableFrom(arg.getClass())){
// 类型相同
supplierArgs[i] = arg;
} else {
// 类型不匹配, 尝试使用json序列化. 当前序列化针对大数据量下性能比较低, 建议将大数据量传输的参数定义到主程序中
String json = OBJECT_MAPPER.writeValueAsString(arg);
Object serializeObject = OBJECT_MAPPER.readValue(json, supplierParameterType);
supplierArgs[i] = serializeObject;
}
}
return supplierArgs;
}
/**
*
* @param invokeReturn
* @param method
* @return
* @throws Throwable Throwable
*/
private Object getReturnObject(Object invokeReturn, Method method) throws Throwable{
if(invokeReturn == null){
return null;
}
Class<?> returnType = method.getReturnType();
if(invokeReturn.getClass().isAssignableFrom(returnType)){
return invokeReturn;
} else {
String json = OBJECT_MAPPER.writeValueAsString(invokeReturn);
return OBJECT_MAPPER.readValue(json, OBJECT_MAPPER.getTypeFactory().constructType(method.getGenericReturnType()) );
}
}
private Method findSupplierMethod(Class<?> supplierClass, String methodName, Class<?>[] supplierArgClasses){
while (supplierClass != null){
Method[] methods = supplierClass.getMethods();
for (Method method : methods) {
String name = method.getName();
if(!Objects.equals(name, methodName)){
continue;
}
if(method.getParameterTypes().length == supplierArgClasses.length){
return method;
}
}
supplierClass = supplierClass.getSuperclass();
}
return null;
}
}

View File

@ -0,0 +1,109 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.oneself;
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import com.gitee.starblues.bootstrap.annotation.OneselfConfig;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.utils.AnnotationUtils;
import com.gitee.starblues.utils.ObjectUtils;
import com.gitee.starblues.utils.ResourceUtils;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.util.ClassUtils;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
/**
*
*
* @author starBlues
* @version 3.0.0
* @since 3.0.0
*/
public class ConfigureMainPluginEnvironment {
private final ProcessorContext processorContext;
private final List<PropertySourceLoader> propertySourceLoaders;
public ConfigureMainPluginEnvironment(ProcessorContext processorContext) {
this.processorContext = processorContext;
this.propertySourceLoaders = new ArrayList<>(2);
this.propertySourceLoaders.add(new YamlPropertySourceLoader());
this.propertySourceLoaders.add(new PropertiesPropertySourceLoader());
}
public void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
SpringPluginBootstrap springPluginBootstrap = processorContext.getSpringPluginBootstrap();
OneselfConfig oneselfConfig = AnnotationUtils.findAnnotation(springPluginBootstrap.getClass(),
OneselfConfig.class);
if(oneselfConfig == null){
return;
}
String[] mainConfigFileName = oneselfConfig.mainConfigFileName();
if(mainConfigFileName.length == 0){
return;
}
for (String fileName : mainConfigFileName) {
load(environment, fileName);
}
}
private void load(ConfigurableEnvironment environment, String fileName){
String fileSuffix = ResourceUtils.getFileSuffix(fileName);
if(ObjectUtils.isEmpty(fileSuffix)){
return;
}
PropertySourceLoader sourceLoader = null;
for (PropertySourceLoader propertySourceLoader : propertySourceLoaders) {
String[] fileExtensions = propertySourceLoader.getFileExtensions();
for (String fileExtension : fileExtensions) {
if(fileSuffix.equalsIgnoreCase(fileExtension)){
sourceLoader = propertySourceLoader;
break;
}
}
}
if(sourceLoader == null){
return;
}
URL url = Objects.requireNonNull(ClassUtils.getDefaultClassLoader()).getResource(fileName);
if(url == null){
return;
}
try {
Path path = Paths.get(url.toURI());
Resource resource = new FileSystemResource(path);
List<PropertySource<?>> propertySources = sourceLoader.load(fileName, resource);
for (PropertySource<?> propertySource : propertySources) {
environment.getPropertySources().addFirst(propertySource);
}
} catch (Exception e){
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,54 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.oneself;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorException;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.integration.operator.EmptyPluginOperator;
import com.gitee.starblues.integration.user.DefaultPluginUser;
import com.gitee.starblues.spring.extract.DefaultOpExtractFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
/**
*
*
* @author starBlues
* @version 3.1.0
* @since 3.0.4
*/
public class OneselfProcessor implements SpringPluginProcessor {
@Override
public void initialize(ProcessorContext context) throws ProcessorException {
registerMainBean(context.getApplicationContext());
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.ONESELF;
}
private void registerMainBean(GenericApplicationContext applicationContext){
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
beanFactory.registerSingleton("extractFactory", new DefaultOpExtractFactory());
beanFactory.registerSingleton("pluginUser", new DefaultPluginUser(applicationContext));
beanFactory.registerSingleton("pluginOperator", new EmptyPluginOperator());
}
}

View File

@ -0,0 +1,42 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.scanner;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
/**
* classpath bean
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class PluginClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public PluginClassPathBeanDefinitionScanner(ProcessorContext processorContext) {
this(processorContext, true);
}
public PluginClassPathBeanDefinitionScanner(ProcessorContext processorContext, boolean useDefaultFilters) {
super(processorContext.getApplicationContext(), useDefaultFilters,
processorContext.getApplicationContext().getEnvironment(),
processorContext.getResourceLoader());
}
}

View File

@ -0,0 +1,266 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.web;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorException;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.bootstrap.utils.AnnotationUtils;
import com.gitee.starblues.bootstrap.utils.DestroyUtils;
import com.gitee.starblues.integration.IntegrationConfiguration;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.SpringBeanFactory;
import com.gitee.starblues.utils.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
/**
* Controller
*
* @author starBlues
* @since 3.0.0
* @version 3.1.1
*/
public class PluginControllerProcessor implements SpringPluginProcessor {
private final static Logger LOG = LoggerFactory.getLogger(PluginControllerProcessor.class);
static final String PROCESS_CONTROLLERS = "PROCESS_SUCCESS";
private RequestMappingHandlerMapping requestMappingHandlerMapping;
private RequestMappingHandlerAdapter handlerAdapter;
private final AtomicBoolean canRegistered = new AtomicBoolean(false);
@Override
public void initialize(ProcessorContext processorContext) throws ProcessorException {
MainApplicationContext mainApplicationContext = processorContext.getMainApplicationContext();
this.requestMappingHandlerMapping = mainApplicationContext.getRequestMappingHandlerMapping();
this.handlerAdapter = mainApplicationContext.getRequestMappingHandlerAdapter();
canRegistered.set(true);
}
@Override
public void refreshBefore(ProcessorContext processorContext) throws ProcessorException {
if(!canRegistered.get()){
return;
}
GenericApplicationContext applicationContext = processorContext.getApplicationContext();
applicationContext.getDefaultListableBeanFactory()
.addBeanPostProcessor(new ControllerPostProcessor(processorContext));
}
@Override
public void refreshAfter(ProcessorContext processorContext) throws ProcessorException {
if(!canRegistered.get()){
return;
}
String pluginId = processorContext.getPluginDescriptor().getPluginId();
List<ControllerWrapper> controllerWrappers = processorContext.getRegistryInfo(PROCESS_CONTROLLERS);
if(ObjectUtils.isEmpty(controllerWrappers)){
return;
}
GenericApplicationContext applicationContext = processorContext.getApplicationContext();
Iterator<ControllerWrapper> iterator = controllerWrappers.iterator();
String pathPrefix = PluginConfigUtils.getPluginRestPrefix(processorContext.getConfiguration(), pluginId);
PluginRequestMappingHandlerMapping pluginHandlerMapping = new PluginRequestMappingHandlerMapping(pathPrefix);
while (iterator.hasNext()){
ControllerWrapper controllerWrapper = iterator.next();
if(!applicationContext.containsBean(controllerWrapper.getBeanName())){
iterator.remove();
}
Object controllerBean = applicationContext.getBean(controllerWrapper.getBeanName());
pluginHandlerMapping.registerHandler(controllerBean);
List<RegisterMappingInfo> registerMappingInfo = pluginHandlerMapping.getAndClear();
Set<RequestMappingInfo> requestMappingInfoSet = new HashSet<>(registerMappingInfo.size());
for (RegisterMappingInfo mappingInfo : registerMappingInfo) {
RequestMappingInfo requestMappingInfo = mappingInfo.getRequestMappingInfo();
requestMappingHandlerMapping.registerMapping(
requestMappingInfo,
mappingInfo.getHandler(),
mappingInfo.getMethod()
);
LOG.info("插件[{}]注册接口: {}", pluginId, requestMappingInfo);
requestMappingInfoSet.add(requestMappingInfo);
}
controllerWrapper.setRequestMappingInfo(requestMappingInfoSet);
}
}
@Override
public void close(ProcessorContext context) throws ProcessorException {
List<ControllerWrapper> controllerWrappers = context.getRegistryInfo(PROCESS_CONTROLLERS);
if(ObjectUtils.isEmpty(controllerWrappers)){
return;
}
for (ControllerWrapper controllerWrapper : controllerWrappers) {
unregister(controllerWrapper);
}
controllerWrappers.clear();
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.PLUGIN;
}
/**
* Controller
* @param controllerBeanWrapper controllerBean
*/
private void unregister(ControllerWrapper controllerBeanWrapper) {
Set<RequestMappingInfo> requestMappingInfoSet = controllerBeanWrapper.getRequestMappingInfo();
if(requestMappingInfoSet != null && !requestMappingInfoSet.isEmpty()){
for (RequestMappingInfo requestMappingInfo : requestMappingInfoSet) {
requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
}
}
if(handlerAdapter != null){
Class<?> beanClass = controllerBeanWrapper.getBeanClass();
DestroyUtils.destroyValue(handlerAdapter, "sessionAttributesHandlerCache", beanClass);
DestroyUtils.destroyValue(handlerAdapter, "initBinderCache", beanClass);
DestroyUtils.destroyValue(handlerAdapter, "modelAttributeCache", beanClass);
}
}
private static class ControllerPostProcessor implements BeanPostProcessor {
private final static Logger LOG = LoggerFactory.getLogger(ControllerPostProcessor.class);
private final ProcessorContext processorContext;
private ControllerPostProcessor(ProcessorContext processorContext) {
this.processorContext = processorContext;
}
@SuppressWarnings("unchecked")
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> aClass = bean.getClass();
RequestMapping requestMapping = AnnotationUtils.findAnnotation(aClass, RequestMapping.class);
boolean isController = AnnotationUtils.existOr(aClass, new Class[]{
Controller.class, RestController.class
});
if(requestMapping != null && isController){
addControllerWrapper(beanName, aClass);
}
return bean;
}
private void addControllerWrapper(String beanName, Class<?> aClass){
List<ControllerWrapper> controllerWrappers = processorContext.getRegistryInfo(PROCESS_CONTROLLERS);
if(controllerWrappers == null){
controllerWrappers = new ArrayList<>();
processorContext.addRegistryInfo(PROCESS_CONTROLLERS, controllerWrappers);
}
ControllerWrapper controllerWrapper = new ControllerWrapper();
controllerWrapper.setBeanName(beanName);
controllerWrapper.setBeanClass(aClass);
controllerWrappers.add(controllerWrapper);
}
}
@Data
static class ControllerWrapper{
/**
* controller bean
*/
private String beanName;
/**
* controller bean
*/
private Class<?> beanClass;
/**
* controller RequestMappingInfo
*/
private Set<RequestMappingInfo> requestMappingInfo;
}
private static class PluginRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
private final List<RegisterMappingInfo> registerMappingInfo = new ArrayList<>();
public PluginRequestMappingHandlerMapping(){
this(null);
}
public PluginRequestMappingHandlerMapping(String pathPrefix){
if(!ObjectUtils.isEmpty(pathPrefix)){
Map<String, Predicate<Class<?>>> prefixes = new HashMap<>();
prefixes.put(pathPrefix, c->true);
setPathPrefixes(prefixes);
}
}
public void registerHandler(Object handler){
detectHandlerMethods(handler);
}
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
super.registerHandlerMethod(handler, method, mapping);
registerMappingInfo.add(new RegisterMappingInfo(handler, method, mapping));
}
public List<RegisterMappingInfo> getAndClear(){
List<RegisterMappingInfo> registerMappingInfo = new ArrayList<>(this.registerMappingInfo);
this.registerMappingInfo.clear();
return registerMappingInfo;
}
}
@AllArgsConstructor
@Getter
private static class RegisterMappingInfo{
private final Object handler;
private final Method method;
private final RequestMappingInfo requestMappingInfo;
}
}

View File

@ -0,0 +1,164 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.web;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorException;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.bootstrap.processor.interceptor.PluginInterceptorRegister;
import com.gitee.starblues.bootstrap.processor.interceptor.PluginInterceptorRegistry;
import com.gitee.starblues.bootstrap.utils.SpringBeanUtils;
import com.gitee.starblues.integration.IntegrationConfiguration;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class PluginInterceptorsProcessor implements SpringPluginProcessor {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final static String INTERCEPTORS = "pluginHandlerInterceptors";
private List<AbstractHandlerMapping> handlerMappings;
@Override
public void initialize(ProcessorContext context) throws ProcessorException {
MainApplicationContext applicationContext = context.getMainApplicationContext();
handlerMappings = SpringBeanCustomUtils.getBeans(applicationContext,
AbstractHandlerMapping.class);
if(handlerMappings.isEmpty()){
logger.warn("Not found AbstractHandlerMapping, Plugin interceptor can't use");
}
}
@Override
public void refreshAfter(ProcessorContext context) throws ProcessorException {
if(handlerMappings.isEmpty()){
return;
}
List<PluginInterceptorRegister> interceptorRegisters = SpringBeanUtils.getBeans(
context.getApplicationContext(),
PluginInterceptorRegister.class);
Map<AbstractHandlerMapping, List<HandlerInterceptor>> handlerInterceptorMap = new HashMap<>();
for (AbstractHandlerMapping handlerMapping : handlerMappings) {
List<HandlerInterceptor> adaptedInterceptors = getAdaptedInterceptors(handlerMapping);
if(!ObjectUtils.isEmpty(adaptedInterceptors)){
handlerInterceptorMap.put(handlerMapping, adaptedInterceptors);
}
}
if(handlerInterceptorMap.isEmpty()){
logger.debug("handlerInterceptorMap is empty");
return;
}
IntegrationConfiguration configuration = context.getConfiguration();
String pluginId = context.getPluginDescriptor().getPluginId();
String pluginRestPrefix = PluginConfigUtils.getPluginRestPrefix(configuration, pluginId);
List<HandlerInterceptor> storeInterceptors = new ArrayList<>();
for (PluginInterceptorRegister interceptorRegister : interceptorRegisters) {
PluginInterceptorRegistry interceptorRegistry = new PluginInterceptorRegistry(pluginRestPrefix);
interceptorRegister.registry(interceptorRegistry);
List<Object> registryInterceptors = interceptorRegistry.getInterceptors();
if(registryInterceptors == null || registryInterceptors.isEmpty()){
continue;
}
for (Object interceptor : registryInterceptors) {
HandlerInterceptor handlerInterceptor = adaptInterceptor(interceptor);
for (List<HandlerInterceptor> value : handlerInterceptorMap.values()) {
value.add(handlerInterceptor);
}
storeInterceptors.add(handlerInterceptor);
}
}
context.addRegistryInfo(INTERCEPTORS, storeInterceptors);
}
@Override
public void close(ProcessorContext context) throws ProcessorException {
if(handlerMappings.isEmpty()){
return;
}
List<HandlerInterceptor> storeInterceptors = context.getRegistryInfo(INTERCEPTORS);
if(ObjectUtils.isEmpty(storeInterceptors)){
return;
}
for (HandlerInterceptor storeInterceptor : storeInterceptors) {
for (AbstractHandlerMapping handlerMapping : handlerMappings) {
List<HandlerInterceptor> adaptedInterceptors = getAdaptedInterceptors(handlerMapping);
if(!ObjectUtils.isEmpty(adaptedInterceptors)){
adaptedInterceptors.remove(storeInterceptor);
}
}
}
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.PLUGIN;
}
/**
*
* @param handlerMapping AbstractHandlerMapping
* @return List<HandlerInterceptor>
*/
private List<HandlerInterceptor> getAdaptedInterceptors(AbstractHandlerMapping handlerMapping){
try {
return ClassUtils.getReflectionField(handlerMapping, "adaptedInterceptors", List.class);
} catch (IllegalAccessException e) {
logger.error("Can't get 'adaptedInterceptors' from AbstractHandlerMapping, so " +
"You can't use HandlerInterceptor. {} ", e.getMessage());
return null;
}
}
/**
*
* @param interceptor interceptor
* @return HandlerInterceptor
*/
private HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
} else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
} else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}
}

View File

@ -0,0 +1,74 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.processor.web;
import com.gitee.starblues.bootstrap.processor.ProcessorContext;
import com.gitee.starblues.bootstrap.processor.ProcessorException;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import com.gitee.starblues.utils.ObjectUtils;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.HashSet;
import java.util.Set;
/**
* web.
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class PluginStaticResourceProcessor implements SpringPluginProcessor {
/**
*
*
* classpath: static/
* file: D://path/test
*/
private final static String STATIC_LOCATIONS = "spring.resources.static-locations";
@Override
public void refreshBefore(ProcessorContext context) throws ProcessorException {
GenericApplicationContext applicationContext = context.getApplicationContext();
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String property = environment.getProperty(STATIC_LOCATIONS);
if(ObjectUtils.isEmpty(property)){
return;
}
String[] staticLocations = property.split(",");
if (ObjectUtils.isEmpty(staticLocations)) {
return;
}
Set<String> staticLocationsSet = new HashSet<>(staticLocations.length);
for (String staticLocation : staticLocations) {
if(ObjectUtils.isEmpty(staticLocation)){
continue;
}
staticLocationsSet.add(staticLocation);
}
context.getWebConfig().setResourceLocations(staticLocationsSet);
}
@Override
public ProcessorContext.RunMode runMode() {
return ProcessorContext.RunMode.PLUGIN;
}
}

View File

@ -0,0 +1,95 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.realize;
import com.gitee.starblues.bootstrap.AutowiredTypeDefinerConfig;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.utils.UrlUtils;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import java.util.HashSet;
import java.util.Set;
/**
* autowiredType
*
* @author starBlues
* @since 3.0.3
* @version 3.0.3
*/
public interface AutowiredTypeDefiner {
/**
* ClassDefiner
* @param config config ClassDefiner
*/
void config(AutowiredTypeDefinerConfig config);
@Getter
@EqualsAndHashCode
class ClassDefiner{
/**
*
*/
private final AutowiredType.Type autowiredType;
/**
*
*/
private final Set<String> classNamePatterns;
private ClassDefiner(AutowiredType.Type autowiredType, Set<String> classNamePatterns){
this.autowiredType = autowiredType;
this.classNamePatterns = classNamePatterns;
}
public static ClassDefiner config(AutowiredType.Type autowiredType, Class<?>... classes){
if(autowiredType == null){
throw new IllegalArgumentException("autowiredType 参数不能为空");
}
int length = classes.length;
if(length == 0){
throw new IllegalArgumentException("classes 参数不能为空");
}
Set<String> classNamePatterns = new HashSet<>(length);
for (Class<?> aClass : classes) {
classNamePatterns.add(UrlUtils.formatMatchUrl(aClass.getName()));
}
return new ClassDefiner(autowiredType, classNamePatterns);
}
public static ClassDefiner config(AutowiredType.Type autowiredType, String... classNamePatterns){
if(autowiredType == null){
throw new IllegalArgumentException("autowiredType 参数不能为空");
}
int length = classNamePatterns.length;
if(length == 0){
throw new IllegalArgumentException("classNamePatterns 参数不能为空");
}
Set<String> classNamePatternsSet = new HashSet<>(length);
for (String classNamePattern : classNamePatterns) {
classNamePatternsSet.add(UrlUtils.formatMatchUrl(classNamePattern));
}
return new ClassDefiner(autowiredType, classNamePatternsSet);
}
}
}

View File

@ -0,0 +1,53 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.realize;
import com.gitee.starblues.core.PluginCloseType;
import com.gitee.starblues.core.PluginInfo;
import com.gitee.starblues.core.descriptor.PluginDescriptor;
import org.springframework.context.support.GenericApplicationContext;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.1.0
*/
public interface PluginCloseListener {
/**
*
* @param descriptor
* @deprecated 3.1.1
* @since 3.0.0
*/
default void close(PluginDescriptor descriptor){}
/**
*
* @param applicationContext ApplicationContext
* @param pluginInfo
* @param closeType
* @since 3.1.0
*/
default void close(GenericApplicationContext applicationContext,
PluginInfo pluginInfo, PluginCloseType closeType){
close(pluginInfo != null ? pluginInfo.getPluginDescriptor() : null);
}
}

View File

@ -0,0 +1,95 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.realize;
/**
* .
*
* @author starBlues
* @since 3.0.0
* @version 3.0.3
*/
public interface StopValidator {
/**
* /. /
* @return
* @since 3.0.0
*/
Result verify();
class Result{
/**
*
*/
private final boolean verify;
/**
*
*/
private String message;
public Result(boolean verify) {
this.verify = verify;
}
public Result(boolean verify, String message) {
this.verify = verify;
this.message = message;
}
/**
*
* @return Result
* @since 3.0.3
*/
public static Result ok(){
return new Result(true);
}
/**
*
* @return Result
* @since 3.0.3
*/
public static Result forbid(){
return forbid(null);
}
/**
*
* @param message
* @return Result
* @since 3.0.3
*/
public static Result forbid(String message){
return new Result(false, message);
}
public boolean isVerify() {
return verify;
}
public String getMessage() {
return message;
}
}
}

View File

@ -0,0 +1,64 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.utils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class AnnotationUtils {
private AnnotationUtils(){}
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
return org.springframework.core.annotation.AnnotationUtils.findAnnotation(method, annotationType);
}
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
return org.springframework.core.annotation.AnnotationUtils.findAnnotation(clazz, annotationType);
}
public static <A extends Annotation> boolean existOr(Class<?> clazz, Class<A>[] annotationTypes) {
for (Class<A> annotationType : annotationTypes) {
A annotation = findAnnotation(clazz, annotationType);
if(annotation != null){
return true;
}
}
return false;
}
public static <A extends Annotation> boolean existAnd(Class<?> clazz, Class<A>[] annotationTypes) {
for (Class<A> annotationType : annotationTypes) {
A annotation = findAnnotation(clazz, annotationType);
if(annotation == null){
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,103 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.utils;
import com.gitee.starblues.utils.ReflectionUtils;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
/**
*
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class DestroyUtils {
private DestroyUtils(){}
public static void destroyAll(Object object, String fieldName, Class<?> fieldType){
destroyAll(object, object.getClass(), fieldName, fieldType);
}
public static void destroyAll(Object object, Class<?> objectClass, String fieldName, Class<?> fieldType){
try {
Object fieldObject = ReflectionUtils.getField(object, objectClass, fieldName, fieldType);
if(fieldObject == null){
return;
}
destroyAll(fieldObject);
} catch (Exception e){
// 忽略
}
}
public static void destroyValue(Object object, String fieldName, Object value){
destroyValue(object, object.getClass(), fieldName, value);
}
public static void destroyValue(Object object, Class<?> objectClass, String fieldName, Object value){
destroyValue(object, objectClass, fieldName, null, value);
}
public static void destroyValue(Object object, Class<?> objectClass, String fieldName, Class<?> fieldType, Object value){
try {
Object fieldObject = ReflectionUtils.getField(object, objectClass, fieldName, fieldType);
if(fieldObject == null){
return;
}
destroyValue(fieldObject, value);
} catch (Exception e){
// 忽略
}
}
@SuppressWarnings("all")
public static void destroyAll(Object object){
if(object == null){
return;
}
if(object instanceof Map){
((Map)object).clear();
} else if (object instanceof Collection){
((Collection)object).clear();
} else if(object.getClass().isArray()){
Object[] array = (Object[])object;
for (int i = 0; i < array.length; i++) {
array[i] = null;
}
}
}
@SuppressWarnings("all")
public static void destroyValue(Object object, Object value){
if(object == null){
return;
}
if(object instanceof Map){
((Map)object).remove(value);
} else if (object instanceof Collection){
((Collection) object).removeIf(next -> Objects.equals(next, value));
}
}
}

View File

@ -0,0 +1,43 @@
/**
* Copyright [2019-Present] [starBlues]
*
* 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 com.gitee.starblues.bootstrap.utils;
import com.gitee.starblues.bootstrap.processor.SpringPluginProcessor;
import java.util.List;
import java.util.function.Supplier;
/**
* ProcessorUtils
*
* @author starBlues
* @since 3.0.0
* @version 3.0.0
*/
public class ProcessorUtils {
public static void add(List<SpringPluginProcessor> pluginProcessors, Supplier<SpringPluginProcessor> supplier){
try {
SpringPluginProcessor pluginProcessor = supplier.get();
pluginProcessors.add(pluginProcessor);
} catch (Throwable e){
// 忽略
}
}
}

Some files were not shown because too many files have changed in this diff Show More