vinophantom
1/13/2019 - 12:28 PM

spring

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("-", "");
    }

}