spring
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="core" />
<module name="test" />
<module name="utils" />
</profile>
</annotationProcessing>
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AlibabaAvoidCommentBehindStatement" enabled="false" level="MAJOR" enabled_by_default="false" />
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
<option name="TOP_LEVEL_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="INNER_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="METHOD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
</value>
</option>
<option name="FIELD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="IGNORE_DEPRECATED" value="false" />
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
<option name="IGNORE_DUPLICATED_THROWS" value="false" />
<option name="IGNORE_POINT_TO_ITSELF" value="false" />
<option name="myAdditionalJavadocTags" value="date" />
</inspection_tool>
</profile>
</component>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
<option value="$PROJECT_DIR$/core/pom.xml" />
<option value="$PROJECT_DIR$/utils/pom.xml" />
</list>
</option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/ioc/pom.xml" />
</set>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />
<?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>
<groupId>com.vino.myspring</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.vino.myspring</groupId>
<artifactId>utils</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
</dependencies>
</project>
package com.vino.myspring.framework.core.annotation;
import com.vino.myspring.framework.core.aop.AopAction;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Around {
Class<? extends AopAction>[] value();
}
package com.vino.myspring.framework.core.annotation;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Aspect {
String value();
String cls() default "";
}
package com.vino.myspring.framework.core.annotation;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
String value() default "";
}
package com.vino.myspring.framework.core.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
String value() default "";
}
package com.vino.myspring.framework.core.annotation;
import com.vino.myspring.framework.core.aop.AopAction;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Clear {
Class<? extends AopAction>[] value() default {};
}
package com.vino.myspring.framework.core.annotation;
import java.lang.annotation.*;
/**
* 作用于类上标注为配置类,作用于方法上可执行无参忽略返回值的方法
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Configuration {
int value() default 0;
}
package com.vino.myspring.framework.core.annotation;
import java.lang.annotation.*;
/**
* 通过value的值可控制loader执行顺序,从小到大执行
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Loader {
int value() default Integer.MAX_VALUE;
}
package com.vino.myspring.framework.core.annotation;
import java.lang.annotation.*;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Param {
String value();
}
package com.vino.myspring.framework.core.aop;
public abstract class AopAction {
public abstract void invoke(Invocation invocation) throws Throwable;
}
package com.vino.myspring.framework.core.aop;
import com.vino.myspring.framework.core.annotation.Around;
import com.vino.myspring.framework.core.annotation.Clear;
import com.vino.myspring.framework.core.ioc.BeanContainer;
import com.vino.myspring.utiils.CollectionKit;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class AopCallback implements MethodInterceptor {
private Object target;
public AopCallback(Object target) {
this.target = target;
}
public Object getTarget() {
return target;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
List<AopAction> actionList = getAopActionChain(method);
if (CollectionKit.isEmptyCollection(actionList)) {
return methodProxy.invoke(target, args);
}
return new Invocation(target, method, args, methodProxy, actionList).invoke().getReturnVal();
}
private List<AopAction> getAopActionChain(Method method) {
List<AopAction> actionList = AopContainer.getAopActionChain(method);
if (actionList != null) {
return actionList;
}
actionList = AopContainer.getClassAopActionChain(target.getClass());//获取类拦截器
if (!method.isAnnotationPresent(Around.class)) {
return actionList;
}
if (actionList == null) {
actionList = new ArrayList<>();
}
if (method.isAnnotationPresent(Clear.class)) {
//方法上有LSClear注解就清除切面
Class<? extends AopAction>[] clearClasses = method.getAnnotation(Clear.class).value();
if (CollectionKit.isEmptyArray(clearClasses)) {
actionList.clear(); //清除所有切面
} else {
//清除指定切面
actionList = actionList.stream()
.filter(aopAction -> !CollectionKit.inArray(clearClasses, aopAction.getClass()))
.collect(Collectors.toList());
}
}
Around lsAround = method.getAnnotation(Around.class);
for (Class<? extends AopAction> aopActionClass : lsAround.value()) {
AopAction aopAction = BeanContainer.getBean(aopActionClass);
actionList.add(aopAction);
}
AopContainer.putAopActionChain(method, actionList);
return actionList;
}
}
package com.vino.myspring.framework.core.aop;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 维护Aop拦截链缓存
*/
public class AopContainer {
private final static Map<Class<?>, List<AopAction>> classAopActionChainMap = new HashMap<>();
private final static Map<Method, List<AopAction>> aopActionCache = new ConcurrentHashMap<>();
public static List<AopAction> getAopActionChain(Method key) {
return aopActionCache.get(key);
}
public static void putAopActionChain(Method key, List<AopAction> value) {
aopActionCache.put(key, value);
}
public static List<AopAction> getClassAopActionChain(Class<?> key) {
return classAopActionChainMap.get(key);
}
public static List<AopAction> getClassAopActionChainOrNew(Class<?> key) {
List<AopAction> actionList = getClassAopActionChain(key);
if (actionList == null) {
actionList = new ArrayList<>();
}
return actionList;
}
public static List<AopAction> putClassAopActionChain(Class<?> key, List<AopAction> value) {
return classAopActionChainMap.put(key, value);
}
}
package com.vino.myspring.framework.core.aop;
import com.vino.myspring.framework.core.annotation.Around;
import com.vino.myspring.framework.core.ioc.BeanContainer;
import com.vino.myspring.utiils.ClassUtil;
import com.vino.myspring.utiils.CollectionKit;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import java.util.List;
/**
* 初始化Aop、Aop强化方法
* @author Administrator
*
*/
public class AopHelper {
public static <T> T enhance(T obj) {
if (!ClassUtil.hasAnnotation(obj.getClass(), Around.class)
&& CollectionKit.isEmptyCollection(AopContainer.getClassAopActionChain(obj.getClass()))) {
return obj;
//切面列表为空且整个类里没有LSAround注解的类不加强,会牺牲启动时的速度,避免有不需要加强的类里的public属性丢失
// ,当然个人还是习惯所有属性私有加getter/setter
}
if (Enhancer.isEnhanced(obj.getClass())) {
return obj;
}
try {
return (T) Enhancer.create(obj.getClass(), (Callback) new AopCallback(obj));
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
public static void addClassAopAction(Class<?> targetClass, Class<?> aopActionClass) {
List<AopAction> actionList = AopContainer.getClassAopActionChainOrNew(targetClass);
AopAction aopAction = (AopAction) BeanContainer.getBean(aopActionClass);
actionList.add(aopAction);
AopContainer.putClassAopActionChain(targetClass, actionList);
}
}
package com.vino.myspring.framework.core.aop;
import com.vino.myspring.framework.core.annotation.Around;
import com.vino.myspring.framework.core.annotation.Aspect;
import com.vino.myspring.framework.core.annotation.Bean;
import com.vino.myspring.framework.core.ioc.BeanContainer;
import com.vino.myspring.framework.core.loader.ClassLoader;
import com.vino.myspring.utiils.ClassUtil;
import com.vino.myspring.utiils.StringKit;
import java.util.Map;
import java.util.Set;
@com.vino.myspring.framework.core.annotation.Loader(100)
public class AopLoader implements ClassLoader {
@Override
public void doLoad(Set<Class<?>> classSet) {
// AOP强化
createChainsByAopAction(classSet);
createChainsByAnnotation(classSet);
enhanceBeanContainer();
}
private void enhanceBeanContainer() {
Map<String, Object> beanMap = BeanContainer.getBeanMap();
//对bean容器里的bean进行强化(生成代理对象)
for (Map.Entry<String, Object> entry : beanMap.entrySet()) {
Object obj = entry.getValue();
// || !obj.getClass().isAnnotationPresent(LSBean.class)
Class<?> clazz = obj.getClass();
if (clazz.isAssignableFrom(AopAction.class)) {
continue; //不强化Aop拦截类
}
Object enhanceInstance = AopHelper.enhance(obj);
beanMap.put(entry.getKey(), enhanceInstance);
}
}
private void createChainsByAnnotation(Set<Class<?>> classSet) {
//扫描LSAround注解的类
Set<Class<?>> classes = ClassUtil.getClassesByAnnotation(classSet, Around.class);
for (Class<?> clazz : classes) {
if (!BeanContainer.containsKey(clazz.getName())) {
continue;
}
Around lsAround = clazz.getAnnotation(Around.class);
for (Class<?> aopActionClass : lsAround.value()) {
AopHelper.addClassAopAction(clazz, aopActionClass);
}
}
}
private void createChainsByAopAction(Set<Class<?>> classSet) {
//扫描所有继承AopAction的类,如果有LSAspect注解就添加到缓存
Set<Class<?>> aopActionClasses = ClassUtil.getClassesBySuper(classSet, AopAction.class);
for (Class<?> clazz : aopActionClasses) {
if (!clazz.isAnnotationPresent(Aspect.class) || !clazz.isAnnotationPresent(Bean.class)) {
continue;
}
Aspect aspect = clazz.getAnnotation(Aspect.class);
String pkg = aspect.value();
String cls = aspect.cls();
if (StringKit.notBlank(cls)) {
String clsName = pkg + "." + cls;
try {
Class<?> targetClass = Class.forName(clsName);
AopHelper.addClassAopAction(targetClass, clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else {
ClassUtil.getClassesByPkg(classSet, pkg).forEach(targetClass -> {
AopHelper.addClassAopAction(targetClass, clazz);
});
}
}
}
}
package com.vino.myspring.framework.core.aop;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.List;
public class Invocation {
private Object target;
private Method method;
private Object[] args;
private MethodProxy methodProxy;
private Object returnVal = null;
private List<AopAction> aopActionList;
private int invokePos = 0;
public Invocation(Object target, Method method, Object[] args, MethodProxy methodProxy, List<AopAction> aopActionList) {
this.target = target;
this.method = method;
this.args = args;
this.methodProxy = methodProxy;
this.aopActionList = aopActionList;
}
public Invocation invoke() throws Throwable {
if (invokePos < aopActionList.size()) {
aopActionList.get(invokePos++).invoke(this);
} else {
returnVal = methodProxy.invoke(target, args);
}
return this;
}
public Object getReturnVal() {
return returnVal;
}
public void setReturnVal(Object returnVal) {
this.returnVal = returnVal;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public MethodProxy getMethodProxy() {
return methodProxy;
}
public void setMethodProxy(MethodProxy methodProxy) {
this.methodProxy = methodProxy;
}
}
package com.vino.myspring.framework.core.constant;
public class Constants {
public static final int IOC_LOADER_LEVEL = 0;
public static final int AOP_LOADER_LEVEL = 1;
public static final String CONFIG_SCAN_PACKAGE = "app.scanPackage";
public static final String CONFIG_BEANS_CONFIG = "app.beansConfig";
}
package com.vino.myspring.framework.core.context;
import com.vino.myspring.framework.core.annotation.Loader;
import com.vino.myspring.framework.core.constant.Constants;
import com.vino.myspring.framework.core.ioc.BeanContainer;
import com.vino.myspring.framework.core.loader.ClassLoader;
import com.vino.myspring.framework.core.utils.CommUtils;
import com.vino.myspring.utiils.*;
import org.apache.log4j.Logger;
import java.lang.reflect.Modifier;
import java.util.*;
public class ApplicationContext {
private static final Logger logger = Logger.getLogger(ApplicationContext.class);
public ApplicationContext(String configLocation) {
//加载配置文件
PropKit.use(configLocation);
}
public void init() {
Set<Class<?>> classSet = initClassSet();
initLoader(classSet);
}
private Set<Class<?>> initClassSet() {
String scanPackage = PropKit.get(Constants.CONFIG_SCAN_PACKAGE);
if (StringKit.isBlank(scanPackage)) {
throw new RuntimeException("scan package can not be null");
}
System.out.println("开始扫描..." + scanPackage);
//默认扫描框架包名
scanPackage = CommUtils.getLoaderPackageNames() + scanPackage;
//扫描配置包名下的所有类(递归)
Set<Class<?>> classSet = new HashSet<>();
String[] pkgNames = scanPackage.split(",");
for (String packageName : pkgNames) {
Set<Class<?>> list = ClassUtil.scanClassListByPkg(packageName);
if (!CollectionKit.isEmptyCollection(list)) {
classSet.addAll(list);
}
}
return classSet;
}
private void initLoader(Set<Class<?>> classSet) {
ClassUtil.getClassesByInterface(classSet, ClassLoader.class)
.stream()
//排除抽象类
.filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
//只加载Loader注解的类
.filter(clazz -> clazz.isAnnotationPresent(Loader.class))
//对所有loader根据level升序排序
.sorted((clazz1, clazz2) -> {
Loader lsLoader1 = clazz1.getAnnotation(Loader.class);
Loader lsLoader2 = clazz2.getAnnotation(Loader.class);
return lsLoader1.value() - lsLoader2.value();
})
.map(ObjectKit::getInstance)
//过滤掉创建实例失败的Loader
.filter(Objects::nonNull)
.map(o -> (ClassLoader) o)
.forEach(loader -> {
Logger log = Logger.getLogger(loader.getClass());
log.info("loading...");
loader.doLoad(classSet);
log.info("load success");
});
}
public <T> T getBean(Class<T> clazz) {
return BeanContainer.getBean(clazz);
}
public <T> T getBean(String name) {
return BeanContainer.getBean(name);
}
}
package com.vino.myspring.framework.core.exception;
public class CommException extends RuntimeException {
public CommException(String message) {
super(message);
}
public CommException(Throwable cause) {
super(cause);
}
}
package com.vino.myspring.framework.core.exception;
public class DiException extends RuntimeException {
public DiException(String info) {
super("final field can not be inject: " + info);
}
}
package com.vino.myspring.framework.core.ioc;
import com.vino.myspring.framework.core.annotation.Bean;
import com.vino.myspring.utiils.ClassUtil;
import com.vino.myspring.utiils.CollectionKit;
import com.vino.myspring.utiils.StringKit;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class BeanContainer {
private static Map<String, Object> beanMap = new ConcurrentHashMap<>();
public static boolean containsKey(String key) {
return beanMap.containsKey(key);
}
public static <T> T getBean(String key) {
Map<String, Object> m = beanMap;
return (T) beanMap.get(key);
}
public static <T> T getBean(Class<T> clazz) {
return getBean(clazz.getName());
}
public static Object put(String key, Object value) {
return beanMap.put(key, value);
}
public static Collection<Object> allBeans() {
return beanMap.values();
}
public static Map<String, Object> getBeanMap() {
return beanMap;
}
public static void putBeanByAnnotation(Class<?> clazz, Bean lsBean, Object instance) {
String name = lsBean.value().trim();
if (StringKit.notBlank(name)) {
put(name, instance); //这里修改成有注解的名就只按那个名,不再覆盖之前的类名和实现的接口类名
return;
}
put(ClassUtil.getInstanceName(clazz), instance); //先按类名存一次
Class<?>[] interfaces = clazz.getInterfaces();
if (!CollectionKit.isEmptyArray(interfaces)) {//再按实现的接口的类名存一次
for (Class interfaceClass : interfaces) {
put(ClassUtil.getInstanceName(interfaceClass), instance);
}
}
}
}
package com.vino.myspring.framework.core.ioc;
import java.util.List;
import java.util.Map;
public class BeanInfo {
/**
* className : demo.web.TestBean
* properties : {"val1":10,"val2":"123"}
* constructor : {"val1":10,"val2":"123"}
*/
private String name;
private String className;
private Map<String, String> properties;
private List<String> constructor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public List<String> getConstructor() {
return constructor;
}
public void setConstructor(List<String> constructor) {
this.constructor = constructor;
}
}
package com.vino.myspring.framework.core.ioc;
import com.vino.myspring.framework.core.annotation.Autowired;
import com.vino.myspring.framework.core.aop.AopHelper;
import com.vino.myspring.framework.core.exception.DiException;
import com.vino.myspring.utiils.StringKit;
import java.lang.reflect.*;
public class DependencyInjector {
/**
* 遍历bean容器里的所有对象,依次注入
*/
public static void injectAll() {
DependencyInjector injector = new DependencyInjector();
for (Object obj : BeanContainer.allBeans()) {
injector.inject(obj);
}
}
public void inject(Object obj) {
Class<?> clazz = obj.getClass();
injectByField(clazz, obj);
injectBySetMethod(clazz, obj);
}
/**
* 遍历成员变量进行注入
* @param clazz
* @param obj
*/
private void injectByField(Class<?> clazz, Object obj) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Autowired.class)) {
continue;
}
if (Modifier.isFinal(field.getModifiers())) {
throw new DiException(clazz.getName() + ":" + field.getName());
}
try {
field.setAccessible(true);
// if (field.get(obj) != null) {
// continue;//已经有值不覆盖注入
// }
Autowired lsAutowired = field.getAnnotation(Autowired.class);
Object val = getInjectVal(lsAutowired, field.getType().getName());
field.set(obj, val); //注入Aop强化后的对象
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new DiException(e.getMessage());
}
}
}
/**
* 必须是public set开头 只有一个参数 LSAutowired注解的方法才会调用注入
* @param clazz
* @param obj
*/
private void injectBySetMethod(Class<?> clazz, Object obj) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (!method.getName().startsWith("set") || method.getParameterCount() != 1) {
continue;
}
if (!method.isAnnotationPresent(Autowired.class)) {
continue;
}
Autowired lsAutowired = method.getAnnotation(Autowired.class);
Class<?> paramClass = method.getParameterTypes()[0];
Object val = getInjectVal(lsAutowired, paramClass.getName());
try {
method.invoke(obj, val);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
throw new DiException(e.getMessage());
}
}
}
/**
* 尝试根据LSAutowired给的beanName从容器里获取对象,为空就按类名获取
* @param lsAutowired
* @param className
* @return
*/
private Object getInjectVal(Autowired lsAutowired, String className) {
String beanName = lsAutowired.value();
if (StringKit.isBlank(beanName)) {
beanName = className;
}
Object val = BeanContainer.getBean(beanName);
if (val == null) {
// throw new DiException(beanName + "is not found in bean container");
return null;
}
return AopHelper.enhance(val);
}
}
package com.vino.myspring.framework.core.ioc;
import com.vino.myspring.framework.core.ioc.factory.AnnotationBeanFactory;
import com.vino.myspring.framework.core.ioc.factory.ConfigurationBeanFactory;
import com.vino.myspring.framework.core.ioc.factory.JsonBeanFactory;
import com.vino.myspring.framework.core.loader.ClassLoader;
import java.util.Set;
@com.vino.myspring.framework.core.annotation.Loader(10)
public class IocLoader implements ClassLoader {
@Override
public void doLoad(Set<Class<?>> classSet) {
//初始化Bean容器
try {
//扫描class根据注解加载
new AnnotationBeanFactory().loadBean(classSet);
//根据LSConfiguration注解的类里被LSBean修饰的方法加载bean
new ConfigurationBeanFactory().loadBean(classSet);
//从json文件加载bean
new JsonBeanFactory().loadBean(classSet);
} catch (Exception e) {
e.printStackTrace();
}
DependencyInjector.injectAll(); //依赖注入
}
}
package com.vino.myspring.framework.core.ioc.factory;
import com.vino.myspring.framework.core.annotation.Bean;
import com.vino.myspring.framework.core.ioc.BeanContainer;
import com.vino.myspring.utiils.ClassUtil;
import com.vino.myspring.utiils.CollectionKit;
import com.vino.myspring.utiils.ObjectKit;
import java.util.Set;
public class AnnotationBeanFactory implements BeanFactory {
@Override
public void loadBean(Set<Class<?>> classSet) {
if (CollectionKit.isEmptyCollection(classSet)) {
return;
}
//加载Bean注解的类
ClassUtil.getClassesByAnnotation(classSet, Bean.class)
.forEach(clazz -> {
Object instance = ObjectKit.getInstance(clazz);
Bean lsBean = clazz.getAnnotation(Bean.class);
BeanContainer.putBeanByAnnotation(clazz, lsBean, instance);
});
}
}
package com.vino.myspring.framework.core.ioc.factory;
import java.util.Set;
public interface BeanFactory {
void loadBean(Set<Class<?>> classSet);
}
package com.vino.myspring.framework.core.ioc.factory;
import com.vino.myspring.framework.core.annotation.Autowired;
import com.vino.myspring.framework.core.annotation.Bean;
import com.vino.myspring.framework.core.annotation.Configuration;
import com.vino.myspring.framework.core.aop.AopHelper;
import com.vino.myspring.framework.core.exception.CommException;
import com.vino.myspring.framework.core.ioc.BeanContainer;
import com.vino.myspring.utiils.ClassUtil;
import com.vino.myspring.utiils.StringKit;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Set;
public class ConfigurationBeanFactory implements BeanFactory {
@Override
public void loadBean(Set<Class<?>> classSet) {
//加载Configuration注解的类
ClassUtil.getClassesByAnnotation(classSet, Configuration.class)
.stream()
.sorted((o1, o2) -> {
Configuration configuration1 = o1.getAnnotation(Configuration.class);
Configuration configuration2 = o2.getAnnotation(Configuration.class);
return configuration1.value() - configuration2.value();
})
.forEach(this::loadConfiguration);
}
private void loadConfiguration(Class<?> clazz) {
try {
Object configInstance = clazz.newInstance();
Method[] methods = clazz.getMethods();
Arrays.sort(methods, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); //根据名字排序控制加载顺序
for (Method method : methods) {
if (method.isAnnotationPresent(Configuration.class)) {
method.invoke(configInstance); //Configuration注解的方法直接执行
continue;
}
if (!method.isAnnotationPresent(Bean.class)) {
continue;
}
Object[] args = getInjectParams(method);
Object beanInstance = method.invoke(configInstance, args);
Class<?> beanClass = method.getReturnType();
Bean Bean = method.getAnnotation(Bean.class);
BeanContainer.putBeanByAnnotation(beanClass, Bean, beanInstance);
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
}
private Object[] getInjectParams(Method method) {
Parameter[] parameters = method.getParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Class<?> typeClass = parameter.getType();
String beanName = typeClass.getName();
if (parameter.isAnnotationPresent(Autowired.class)) {
Autowired Autowired = parameter.getAnnotation(Autowired.class);
if (StringKit.notBlank(Autowired.value())) {
beanName = Autowired.value();
}
}
Object arg = BeanContainer.getBean(beanName);
if (arg == null) {
throw new CommException(String.format("In %s inject param is null: %s"
, ClassUtil.getFullMethodName(method), beanName));
}
args[i] = AopHelper.enhance(arg);
}
return args;
}
}
package com.vino.myspring.framework.core.ioc.factory;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.vino.myspring.framework.core.aop.AopHelper;
import com.vino.myspring.framework.core.constant.Constants;
import com.vino.myspring.framework.core.exception.CommException;
import com.vino.myspring.framework.core.exception.DiException;
import com.vino.myspring.framework.core.ioc.BeanContainer;
import com.vino.myspring.framework.core.ioc.BeanInfo;
import com.vino.myspring.utiils.*;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JsonBeanFactory implements BeanFactory {
private List<BeanInfo> beanInfoList = null;
private final static Pattern BEAN_REF_PATTERN = Pattern.compile("\\$\\{(\\w+)\\}"); //对象关系占位符正则匹配
private void initBeanInfoList(String configPath) {
InputStream inputStream = ClassUtil.getClassLoader().getResourceAsStream(configPath);
if (inputStream == null) {
return;
}
byte[] buffer = new byte[0];
try {
buffer = new byte[inputStream.available()];
inputStream.read(buffer);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (buffer.length > 0) {
beanInfoList = new Gson().fromJson(new String(buffer), new TypeToken<List<BeanInfo>>(){}.getType()); // gson解析BeanInfo集合
}
}
@Override
public void loadBean(Set<Class<?>> classSet) {
String configPath = PropKit.get(Constants.CONFIG_BEANS_CONFIG);
if (StringKit.isBlank(configPath)) {
throw new CommException("beansConfig path is null, can not load bean");
}
initBeanInfoList(configPath);
if (CollectionKit.isEmptyCollection(beanInfoList)) {
return;
}
beanInfoList.forEach(this::addBeanByBeanInfo);
//修改成先把bean实例存到容器再对属性进行注入
beanInfoList.forEach(beanInfo -> {
Object instance = BeanContainer.getBean(beanInfo.getName());
try {
injectProperty(instance, beanInfo.getProperties(), instance.getClass());
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
throw new CommException(e.getCause());
}
});
}
private void addBeanByBeanInfo(BeanInfo beanInfo) {
String className = beanInfo.getClassName();
String beanName = beanInfo.getName();
if (StringKit.isBlank(beanName) || StringKit.isBlank(className)) {
throw new CommException("beanName or className can not be null");
}
try {
Class<?> clazz = Class.forName(className);
Object instance = getInstanceByConstructor(beanInfo.getConstructor(), clazz);
if (instance == null) {
instance = clazz.newInstance(); //尝试根据构造函数新建实例失败直接调用无参构造函数
}
BeanContainer.put(beanName, instance); // 按定义的名字存一遍
BeanContainer.put(className, instance);// 再按类名存一遍
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据properties的内容对instance进行成员变量注入
* @param instance
* @param propertiesMap
* @param clazz
* @return
* @throws IllegalAccessException
* @throws NoSuchFieldException
*/
private Object injectProperty(Object instance, Map<String, String> propertiesMap, Class<?> clazz) throws IllegalAccessException
, NoSuchFieldException {
//进行成员变量注入
if (propertiesMap != null && propertiesMap.size() > 0) {
for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
String name = entry.getKey();
String value = entry.getValue();
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
if (Modifier.isFinal(field.getModifiers())) {
throw new DiException(clazz.getName() + ":" + field.getName());
}
field.set(instance, getPropertyObj(value, field.getType()));
}
}
return instance;
}
/**
* 尝试根据constructor内容进行构造函数注入并返回实例,constructor内参数长度、顺序必须和某一构造函数一致
* @param constructorParamList
* @param clazz
* @return
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws InstantiationException
*/
private Object getInstanceByConstructor(List<String> constructorParamList, Class<?> clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException {
int constructorParamCount = constructorParamList == null ? 0 : constructorParamList.size();
Object instance = null;
//尝试进行构造函数注入,构造函数参数个数必须与配置文件中的参数个数相同
Constructor[] constructors = clazz.getDeclaredConstructors();
if (constructorParamCount > 0 && constructors.length > 0) {
Constructor targetConstructor = null;
for (Constructor constructor : constructors) {
if (constructor.getParameterCount() == constructorParamCount) {
targetConstructor = constructor;
break;
}
}
if (targetConstructor != null) {
Parameter[] params = targetConstructor.getParameters();
Object[] args = new Object[constructorParamCount];
int pos = 0;
for (Parameter parameter : params) { //填充构造函数参数
Class type = parameter.getType();
String value = constructorParamList.get(pos);
args[pos++] = getPropertyObj(value, type);
}
instance = targetConstructor.newInstance(args);
}
}
return instance;
}
/**
* 获取属性的对象,根据参数占位符判断是否引用其他对象对象,基本类型直接调用工具类转换成相应的类型
* @param value
* @param type
* @return
*/
private Object getPropertyObj(String value, Class type) {
if (StringKit.isBlank(value)) {
return null;
}
Matcher matcher = BEAN_REF_PATTERN.matcher(value);
if (matcher.find()) {
String argName = matcher.group(1);
Object arg = BeanContainer.getBean(argName);
if (arg == null) {
throw new RuntimeException("can not found bean by name is " + argName);
}
if (arg.getClass() != type) {
throw new RuntimeException("can not found bean by name is " + argName + ",type is wrong");
}
return AopHelper.enhance(arg);
} else {
return ConvertUtil.convert(value, type);
}
}
}
package com.vino.myspring.framework.core.loader;
import java.util.Set;
public interface ClassLoader {
void doLoad(Set<Class<?>> classSet);
}
package com.vino.myspring.framework.core.utils;
import com.vino.myspring.framework.core.aop.AopLoader;
import com.vino.myspring.framework.core.ioc.IocLoader;
import com.vino.myspring.utiils.ClassUtil;
public class CommUtils {
public static String getLoaderPackageNames () {
return ClassUtil.getPackageName(IocLoader.class) + "," + ClassUtil.getPackageName(AopLoader.class) + ",";
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4" />
<?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>
<groupId>com.vino.myspring</groupId>
<artifactId>myspring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>utils</module>
<module>test</module>
</modules>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<log4j.version>1.2.9</log4j.version>
<cglib.version>3.2.6</cglib.version>
<junit.version>4.10</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>${cglib.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>myspring</artifactId>
<groupId>com.vino.myspring</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>test</artifactId>
<dependencies>
<dependency>
<groupId>com.vino.myspring</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
package com.vino.demo;
import com.vino.myspring.framework.core.annotation.Bean;
@Bean
public class Bean1 {
public void test () {
System.out.println("Bean1.test()");
}
}
package com.vino.demo;
import com.vino.myspring.framework.core.annotation.Autowired;
import com.vino.myspring.framework.core.annotation.Bean;
@Bean(value = "bean2")
public class Bean2 {
@Autowired(value="bean1")
private Bean1 bean1;
public void test2() {
bean1.test();
}
}
package com.vino.demo;
import com.vino.demo.action.Action;
import com.vino.myspring.framework.core.annotation.Around;
import com.vino.myspring.framework.core.annotation.Autowired;
public class Service {
@Autowired
Service2 service2;
@Autowired("service3")
Service3 service3;
@Around(Action.class)
private void test() {
service2.test();
}
public void test2() {
service3.test();
}
}
package com.vino.demo;
public class Service2 {
public void test() {
System.out.println("Service2.test2");
}
}
package com.vino.demo;
import com.vino.myspring.framework.core.annotation.Bean;
@Bean
public class Service3 {
public void test() {
System.out.println("Service3.test()");
}
}
package com.vino.demo;
import com.vino.myspring.framework.core.annotation.Autowired;
import com.vino.myspring.framework.core.annotation.Bean;
import com.vino.myspring.framework.core.context.ApplicationContext;
import org.junit.Before;
@Bean
public class Test {
@Autowired(value="bean1")
private Bean1 bean1;
private ApplicationContext app;
@Before
public void init() {
app = new ApplicationContext("application.properties");
app.init();
}
@org.junit.Test
public void test1() {
Bean2 b2 = app.getBean("bean2");
b2.test2();
//bean1.test();
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
}
package com.vino.demo.action;
import com.vino.myspring.framework.core.aop.AopAction;
import com.vino.myspring.framework.core.aop.Invocation;
public class Action extends AopAction {
@Override
public void invoke(Invocation invocation) throws Throwable {
}
}
app.scanPackage=com.vino.demo
app.beansConfig=beans.json
//[
// {
// "name": "testBean",
// "className": "com.ls.framework.core.bean.TestBean",
// "properties": {
// "val1": 10,
// "val2": "123"
// }
// },
// {
// "name": "testBean1",
// "className": "com.ls.framework.core.bean.TestBean",
// "properties": {
// "val1": 110,
// "val2": "1223213"
// }
// },
// {
// "name": "testBean2",
// "className": "com.ls.framework.core.bean.TestBean2",
// "constructor": [10, "${testBean}"],
// "properties": {
// "val1": 1,
// "val2": "123"
//// , "testBean": "${testBean1}"
// }
// },
// {
// "name": "circleA",
// "className": "com.ls.framework.core.bean.CircleA",
// "properties": {
// "o": "${circleC}"
// }
// },
// {
// "name": "circleB",
// "className": "com.ls.framework.core.bean.CircleB",
// "properties": {
// "o": "${circleA}"
// }
// },
// {
// "name": "circleC",
// "className": "com.ls.framework.core.bean.CircleC",
// "properties": {
// "o": "${circleB}"
// }
// }
//]
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />
<?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>
<groupId>com.vino.myspring</groupId>
<artifactId>utils</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.vino.myspring.utiils;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
public class ClassUtil {
public static ClassLoader getClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
public static Set<Class<?>> getClassesByAnnotation(Set<Class<?>> classSet, Class<? extends Annotation> annotationClass) {
return classSet.stream()
.filter(clazz -> clazz.isAnnotationPresent(annotationClass))
.collect(Collectors.toSet());
}
public static Set<Class<?>> getClassesBySuper(Set<Class<?>> classSet, Class<?> superClass) {
return classSet.stream()
.filter(superClass::isAssignableFrom)
.collect(Collectors.toSet());
}
public static Set<Class<?>> getClassesByPkg(Set<Class<?>> classSet, String pkg) {
return classSet.stream()
.filter(clazz -> clazz.getName().startsWith(pkg))
.collect(Collectors.toSet());
}
public static Set<Class<?>> getClassesByInterface(Set<Class<?>> classSet, Class<?> interfaceClass) {
return classSet.stream()
.filter(clazz -> CollectionKit.inArray(clazz.getInterfaces(), interfaceClass))
.collect(Collectors.toSet());
}
public static Set<Class<?>> scanClassListByPkg(String packageName) {
// URL url = getClassLoader().getResource(packageName.replace(".", "/"));
if (StringKit.isBlank(packageName)) {
throw new RuntimeException("scan package can not be empty");
}
Set<Class<?>> classSet = new HashSet<>();
try {
Enumeration<URL> urlEnumeration = getClassLoader().getResources(packageName.replace(".", "/"));
while (urlEnumeration.hasMoreElements()) {
URL url = urlEnumeration.nextElement();
// System.out.println(url);
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
addFileClass(classSet, url.getFile(), packageName);
} else if ("jar".equals(protocol)) {
addJarClass(classSet, (JarURLConnection) url.openConnection(), packageName);
}
}
return classSet;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static void addFileClass(Set<Class<?>> classSet, String packagePath, String packageName) {
File classDir = new File(packagePath);
// System.out.println(classDir.exists());
File[] files = classDir.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
}
});
if (CollectionKit.isEmptyArray(files)) {
return ;
}
for (File file : files) {
String fileJavaName = StringKit.isBlank(packageName) ? file.getName() : packageName + '.' + file.getName();
if (file.isDirectory()) {
Set<Class<?>> set = scanClassListByPkg(fileJavaName);
if (set != null) {
classSet.addAll(set);
}
} else {
String className = fileJavaName.replace(".class", "");
addClass(classSet, className);
}
}
}
/**
* 添加jar包里的类
* @param classSet
* @param urlConnection
* @param pkgName
*/
private static void addJarClass(Set<Class<?>> classSet, JarURLConnection urlConnection, String pkgName) {
if (urlConnection == null) { return; }
try {
JarFile jarFile = urlConnection.getJarFile();
if (jarFile == null) { return;}
Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
while (jarEntryEnumeration.hasMoreElements()) {
JarEntry jarEntry = jarEntryEnumeration.nextElement();
String entryName = jarEntry.getName().replaceAll("/", ".");
if (entryName.endsWith(".class") && entryName.startsWith(pkgName)) {
addClass(classSet, entryName.replace(".class", ""));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 根据类名加载类加入结果集
* @param classSet
* @param className
*/
private static void addClass(Set<Class<?>> classSet, String className) {
Class<?> clazz;
try {
clazz = Class.forName(className);
classSet.add(clazz);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Can not load class:" + className);
} catch (NoClassDefFoundError e) {
}
}
public static String getFullMethodName(Method method) {
return String.format("%s.%s", method.getDeclaringClass().getName(), method.getName());
}
public static boolean hasAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) {
if (clazz.isAnnotationPresent(annotationClass)) {
return true;
}
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(annotationClass)) {
return true;
}
}
return false;
}
public static String getPackageName(Class c) {
return c.getPackage().getName();
}
public static String getInstanceName (Class c) {
String className = c.getName();
className = className.substring(className.lastIndexOf(".") + 1);
return Character.toLowerCase(className.charAt(0)) + className.substring(1);
}
}
package com.vino.myspring.utiils;
import java.util.Collection;
import java.util.List;
public class CollectionKit {
public static boolean isEmptyCollection(Collection collection) {
return collection == null || collection.isEmpty();
}
public static boolean isEmptyArray(Object[] arr) {
return arr == null || arr.length == 0;
}
public static boolean inArray(Object[] arr, Object obj) {
if (isEmptyArray(arr))
return false;
for (Object o : arr) {
if (o.equals(obj)) {
return true;
}
}
return false;
}
public static boolean inCollection(Collection collection, Object obj) {
if (isEmptyCollection(collection))
return false;
for (Object o : collection) {
if (o.equals(obj)) {
return true;
}
}
return false;
}
}
package com.vino.myspring.utiils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ConvertUtil {
private static final String datePattern = "yyyy-MM-dd";
private static final String dateTimePattern = "yyyy-MM-dd HH:mm:ss";
public static Object convert(Object obj, Class typeClass){
if (obj == null) {
return null;
}
if (typeClass == String.class)
return obj.toString();
if (typeClass == Integer.class || typeClass == int.class){
return Integer.parseInt(obj.toString());
} else if (typeClass == Long.class || typeClass == long.class){
return Long.parseLong(obj.toString());
} else if (typeClass == Boolean.class || typeClass == boolean.class){
return Boolean.parseBoolean(obj.toString());
} else if (typeClass == Float.class || typeClass == float.class){
return Float.parseFloat(obj.toString());
} else if (typeClass == Double.class || typeClass == double.class){
return Double.parseDouble(obj.toString());
} else if (typeClass == BigDecimal.class){
return new BigDecimal(obj.toString());
} else if (typeClass == BigInteger.class){
return new BigInteger(obj.toString());
} else if (typeClass == Date.class){
SimpleDateFormat simpleDateFormat = null;
String s = obj.toString();
s = s.trim();
if(s.length() > datePattern.length()){//字符串长度大于日期格式按日期时间格式算
simpleDateFormat = new SimpleDateFormat(dateTimePattern);
} else {
simpleDateFormat = new SimpleDateFormat(datePattern);
}
try {
return simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
}
package com.vino.myspring.utiils;
/**
* 辅助使用stream api进行filter
*/
public class ObjectKit {
public static boolean isNull(Object obj) {
return obj == null;
}
public static boolean notNull(Object obj) {
return obj != null;
}
public static Object getInstance(Class<?> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
package com.vino.myspring.utiils;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
public class PropKit {
private static Properties properties = new Properties();
public static void use(String fileName){
InputStream inputStream = null;
inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
try {
properties.load(inputStream);
} catch (IOException e) {
throw new RuntimeException(fileName + "not found!");
} finally {
if(null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String get(String key){
return get(key, "");
}
public static String get(String key, String defaultValue){
return properties.getProperty(key, defaultValue);
}
public static Enumeration<?> propertyNames() {
return properties.propertyNames();
}
}
package com.vino.myspring.utiils;
public class StringKit {
/**
* 首字母变小写
*/
public static String firstCharToLowerCase(String str) {
char firstChar = str.charAt(0);
if (firstChar >= 'A' && firstChar <= 'Z') {
char[] arr = str.toCharArray();
arr[0] += ('a' - 'A');
return new String(arr);
}
return str;
}
/**
* 首字母变大写
*/
public static String firstCharToUpperCase(String str) {
char firstChar = str.charAt(0);
if (firstChar >= 'a' && firstChar <= 'z') {
char[] arr = str.toCharArray();
arr[0] -= ('a' - 'A');
return new String(arr);
}
return str;
}
/**
* 字符串为 null 或者内部字符全部为 ' ' '\t' '\n' '\r' 这四类字符时返回 true
*/
public static boolean isBlank(String str) {
if (str == null) {
return true;
}
int len = str.length();
if (len == 0) {
return true;
}
for (int i = 0; i < len; i++) {
switch (str.charAt(i)) {
case ' ':
case '\t':
case '\n':
case '\r':
// case '\b':
// case '\f':
break;
default:
return false;
}
}
return true;
}
public static boolean notBlank(String str) {
return !isBlank(str);
}
public static boolean notBlank(String... strings) {
if (strings == null || strings.length == 0) {
return false;
}
for (String str : strings) {
if (isBlank(str)) {
return false;
}
}
return true;
}
public static boolean notNull(Object... paras) {
if (paras == null) {
return false;
}
for (Object obj : paras) {
if (obj == null) {
return false;
}
}
return true;
}
public static String toCamelCase(String stringWithUnderline) {
if (stringWithUnderline.indexOf('_') == -1) {
return stringWithUnderline;
}
stringWithUnderline = stringWithUnderline.toLowerCase();
char[] fromArray = stringWithUnderline.toCharArray();
char[] toArray = new char[fromArray.length];
int j = 0;
for (int i=0; i<fromArray.length; i++) {
if (fromArray[i] == '_') {
// 当前字符为下划线时,将指针后移一位,将紧随下划线后面一个字符转成大写并存放
i++;
if (i < fromArray.length) {
toArray[j++] = Character.toUpperCase(fromArray[i]);
}
}
else {
toArray[j++] = fromArray[i];
}
}
return new String(toArray, 0, j);
}
public static String join(String[] stringArray) {
StringBuilder sb = new StringBuilder();
for (String s : stringArray) {
sb.append(s);
}
return sb.toString();
}
public static String join(String[] stringArray, String separator) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<stringArray.length; i++) {
if (i > 0) {
sb.append(separator);
}
sb.append(stringArray[i]);
}
return sb.toString();
}
public static boolean equals(String a, String b) {
return a == null ? b == null : a.equals(b);
}
public static String getRandomUUID() {
return java.util.UUID.randomUUID().toString().replace("-", "");
}
}