diff --git a/README.md b/README.md
index c4aa73a..03e8522 100644
--- a/README.md
+++ b/README.md
@@ -2,5 +2,5 @@
* Support IOC(DONE)
* Support Spring Event(DONE)
-* Support Spring AOP(TODO)
+* Support Spring AOP(DOING)
* Support Annotation Driven(TODO)
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 99d58f3..c2abcf9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,5 +55,18 @@
cglib
3.3.0
+
+
+ org.aspectj
+ aspectjrt
+ 1.9.21.1
+
+
+
+ org.aspectj
+ aspectjweaver
+ 1.8.9
+
+
\ No newline at end of file
diff --git a/src/main/java/cn/abelib/springframework/aop/Advisor.java b/src/main/java/cn/abelib/springframework/aop/Advisor.java
new file mode 100644
index 0000000..5697dae
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/Advisor.java
@@ -0,0 +1,17 @@
+package cn.abelib.springframework.aop;
+
+import org.aopalliance.aop.Advice;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:35
+ */
+public interface Advisor {
+
+ /**
+ * Return the advice part of this aspect. An advice may be an
+ * interceptor, a before advice, a throws advice, etc.
+ */
+ Advice getAdvice();
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/BeforeAdvice.java b/src/main/java/cn/abelib/springframework/aop/BeforeAdvice.java
new file mode 100644
index 0000000..88c4895
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/BeforeAdvice.java
@@ -0,0 +1,14 @@
+package cn.abelib.springframework.aop;
+
+import org.aopalliance.aop.Advice;
+
+/**
+ * Common marker interface for before advice
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:27
+ */
+public interface BeforeAdvice extends Advice {
+
+}
\ No newline at end of file
diff --git a/src/main/java/cn/abelib/springframework/aop/ClassFilter.java b/src/main/java/cn/abelib/springframework/aop/ClassFilter.java
new file mode 100644
index 0000000..db4deaf
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/ClassFilter.java
@@ -0,0 +1,17 @@
+package cn.abelib.springframework.aop;
+
+/**
+ * Filter that restricts matching of a pointcut or introduction to
+ * a given set of target classes.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 0:04
+ */
+public interface ClassFilter {
+
+ /**
+ * Should the pointcut apply to the given interface or target class?
+ */
+ boolean matches(Class> clazz);
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/MethodBeforeAdvice.java b/src/main/java/cn/abelib/springframework/aop/MethodBeforeAdvice.java
new file mode 100644
index 0000000..6d5906d
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/MethodBeforeAdvice.java
@@ -0,0 +1,20 @@
+package cn.abelib.springframework.aop;
+
+import java.lang.reflect.Method;
+
+/**
+ *
+ * Advice invoked before a method is invoked. Such advices cannot
+ * prevent the method call proceeding, unless they throw a Throwable.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:33
+ */
+public interface MethodBeforeAdvice extends BeforeAdvice {
+
+ /**
+ * Callback before a given method is invoked.
+ */
+ void before(Method method, Object[] args, Object target) throws Throwable;
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/MethodMatcher.java b/src/main/java/cn/abelib/springframework/aop/MethodMatcher.java
new file mode 100644
index 0000000..1f6f409
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/MethodMatcher.java
@@ -0,0 +1,33 @@
+package cn.abelib.springframework.aop;
+
+import java.lang.reflect.Method;
+
+/**
+ * Part of a {@link Pointcut}: Checks whether the target method is eligible for advice.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 0:05
+ */
+public interface MethodMatcher {
+
+ /**
+ * Perform static checking whether the given method matches. If this
+ * returns {@code false} or if the {@link #isRuntime()} method
+ * returns {@code false}, no runtime check (i.e. no.
+ */
+ boolean matches(Method method, Class> targetClass);
+
+ /**
+ * Is this MethodMatcher dynamic, that is, must a final call be made on the
+ * {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
+ * runtime even if the 2-arg matches method returns {@code true}
+ */
+ boolean isRuntime();
+
+ /**
+ * Check whether there a runtime (dynamic) match for this method,
+ * which must have matched statically.
+ */
+ boolean matches(Method method, Class> targetClass, Object... args);
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/Pointcut.java b/src/main/java/cn/abelib/springframework/aop/Pointcut.java
new file mode 100644
index 0000000..fe870c1
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/Pointcut.java
@@ -0,0 +1,21 @@
+package cn.abelib.springframework.aop;
+
+/**
+ * Core Spring pointcut abstraction.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 0:03
+ */
+public interface Pointcut {
+
+ /**
+ * Return the ClassFilter for this pointcut.
+ */
+ ClassFilter getClassFilter();
+
+ /**
+ * Return the MethodMatcher for this pointcut.
+ */
+ MethodMatcher getMethodMatcher();
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/PointcutAdvisor.java b/src/main/java/cn/abelib/springframework/aop/PointcutAdvisor.java
new file mode 100644
index 0000000..a082344
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/PointcutAdvisor.java
@@ -0,0 +1,18 @@
+package cn.abelib.springframework.aop;
+
+/**
+ * Superinterface for all Advisors that are driven by a pointcut.
+ * This covers nearly all advisors except introduction advisors,
+ * for which method-level matching doesn't apply.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:37
+ */
+public interface PointcutAdvisor extends Advisor {
+
+ /**
+ * Get the Pointcut that drives this advisor.
+ */
+ Pointcut getPointcut();
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/TargetSource.java b/src/main/java/cn/abelib/springframework/aop/TargetSource.java
new file mode 100644
index 0000000..bf4bb22
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/TargetSource.java
@@ -0,0 +1,33 @@
+package cn.abelib.springframework.aop;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/25 23:41
+ */
+public class TargetSource {
+
+ private final Object target;
+
+ public TargetSource(Object target) {
+ this.target = target;
+ }
+
+ /**
+ * Return the type of targets returned by this {@link TargetSource}.
+ *
Can return null
, although certain usages of a
+ * TargetSource
might just work with a predetermined
+ * target class.
+ */
+ public Class>[] getTargetClass(){
+ return this.target.getClass().getInterfaces();
+ }
+
+ /**
+ * Return a target instance. Invoked immediately before the
+ * AOP framework calls the "target" of an AOP method invocation.
+ */
+ public Object getTarget(){
+ return this.target;
+ }
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/aspectj/AspectJExpressionPointcut.java b/src/main/java/cn/abelib/springframework/aop/aspectj/AspectJExpressionPointcut.java
new file mode 100644
index 0000000..a83ce29
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/aspectj/AspectJExpressionPointcut.java
@@ -0,0 +1,69 @@
+package cn.abelib.springframework.aop.aspectj;
+
+import cn.abelib.springframework.aop.ClassFilter;
+import cn.abelib.springframework.aop.MethodMatcher;
+import cn.abelib.springframework.aop.Pointcut;
+import org.aspectj.weaver.tools.PointcutExpression;
+import org.aspectj.weaver.tools.PointcutParser;
+import org.aspectj.weaver.tools.PointcutPrimitive;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 22:44
+ */
+public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
+ private static final Set SUPPORTED_PRIMITIVES = new HashSet<>();
+
+ static {
+ SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
+ }
+
+ private final PointcutExpression pointcutExpression;
+
+ public AspectJExpressionPointcut(String expression) {
+ PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
+ pointcutExpression = pointcutParser.parsePointcutExpression(expression);
+ }
+
+ @Override
+ public boolean matches(Class> clazz) {
+ return pointcutExpression.couldMatchJoinPointsInType(clazz);
+ }
+
+ @Override
+ public boolean matches(Method method, Class> targetClass) {
+ return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
+ }
+
+ @Override
+ public boolean isRuntime() {
+ return this.pointcutExpression.mayNeedDynamicTest();
+ }
+
+ /**
+ * TODO
+ * @param method
+ * @param targetClass
+ * @param args
+ * @return
+ */
+ @Override
+ public boolean matches(Method method, Class> targetClass, Object... args) {
+ return false;
+ }
+
+ @Override
+ public ClassFilter getClassFilter() {
+ return this;
+ }
+
+ @Override
+ public MethodMatcher getMethodMatcher() {
+ return this;
+ }
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/aspectj/AspectJExpressionPointcutAdvisor.java b/src/main/java/cn/abelib/springframework/aop/aspectj/AspectJExpressionPointcutAdvisor.java
new file mode 100644
index 0000000..5ca3d7e
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/aspectj/AspectJExpressionPointcutAdvisor.java
@@ -0,0 +1,43 @@
+package cn.abelib.springframework.aop.aspectj;
+
+import cn.abelib.springframework.aop.Pointcut;
+import cn.abelib.springframework.aop.PointcutAdvisor;
+import org.aopalliance.aop.Advice;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:38
+ */
+public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {
+
+ private AspectJExpressionPointcut pointcut;
+
+ private Advice advice;
+
+ private String expression;
+
+ public void setExpression(String expression){
+ this.expression = expression;
+ }
+
+ public String getExpression() {
+ return expression;
+ }
+
+ @Override
+ public Pointcut getPointcut() {
+ if (null == pointcut) {
+ pointcut = new AspectJExpressionPointcut(expression);
+ }
+ return pointcut;
+ }
+
+ public Advice getAdvice() {
+ return advice;
+ }
+
+ public void setAdvice(Advice advice){
+ this.advice = advice;
+ }
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/AdvisedSupport.java b/src/main/java/cn/abelib/springframework/aop/framework/AdvisedSupport.java
new file mode 100644
index 0000000..aa86a16
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/AdvisedSupport.java
@@ -0,0 +1,53 @@
+package cn.abelib.springframework.aop.framework;
+
+import cn.abelib.springframework.aop.MethodMatcher;
+import cn.abelib.springframework.aop.TargetSource;
+import org.aopalliance.intercept.MethodInterceptor;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 22:43
+ */
+public class AdvisedSupport {
+ // ProxyConfig
+ private boolean proxyTargetClass = false;
+
+ private TargetSource targetSource;
+
+ private MethodInterceptor methodInterceptor;
+
+ private MethodMatcher methodMatcher;
+
+ public boolean isProxyTargetClass() {
+ return proxyTargetClass;
+ }
+
+ public void setProxyTargetClass(boolean proxyTargetClass) {
+ this.proxyTargetClass = proxyTargetClass;
+ }
+
+ public TargetSource getTargetSource() {
+ return targetSource;
+ }
+
+ public void setTargetSource(TargetSource targetSource) {
+ this.targetSource = targetSource;
+ }
+
+ public MethodInterceptor getMethodInterceptor() {
+ return methodInterceptor;
+ }
+
+ public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
+ this.methodInterceptor = methodInterceptor;
+ }
+
+ public MethodMatcher getMethodMatcher() {
+ return methodMatcher;
+ }
+
+ public void setMethodMatcher(MethodMatcher methodMatcher) {
+ this.methodMatcher = methodMatcher;
+ }
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/AopProxy.java b/src/main/java/cn/abelib/springframework/aop/framework/AopProxy.java
new file mode 100644
index 0000000..eded90a
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/AopProxy.java
@@ -0,0 +1,22 @@
+package cn.abelib.springframework.aop.framework;
+
+/**
+ * Delegate interface for a configured AOP proxy, allowing for the creation
+ * of actual proxy objects.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 22:44
+ */
+public interface AopProxy {
+
+ /**
+ * Create a new proxy object.
+ */
+ Object getProxy();
+
+ /**
+ * Create a new proxy object.
+ */
+ Object getProxy(ClassLoader classLoader);
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/CglibAopProxy.java b/src/main/java/cn/abelib/springframework/aop/framework/CglibAopProxy.java
new file mode 100644
index 0000000..cb18fc3
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/CglibAopProxy.java
@@ -0,0 +1,71 @@
+package cn.abelib.springframework.aop.framework;
+
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 22:46
+ */
+public class CglibAopProxy implements AopProxy {
+
+ private final AdvisedSupport advised;
+
+ public CglibAopProxy(AdvisedSupport advised) {
+ this.advised = advised;
+ }
+
+ @Override
+ public Object getProxy() {
+ return this.getProxy(null);
+ }
+
+ @Override
+ public Object getProxy(ClassLoader classLoader) {
+ Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
+ enhancer.setInterfaces(advised.getTargetSource().getTargetClass());
+ if (Objects.nonNull(classLoader)) {
+ enhancer.setClassLoader(classLoader);
+ }
+ enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
+ return enhancer.create();
+ }
+
+ private static class DynamicAdvisedInterceptor implements MethodInterceptor {
+ private final AdvisedSupport advised;
+
+ public DynamicAdvisedInterceptor(AdvisedSupport advised) {
+ this.advised = advised;
+ }
+
+ @Override
+ public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
+ CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy);
+ if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
+ return advised.getMethodInterceptor().invoke(methodInvocation);
+ }
+ return methodInvocation.proceed();
+ }
+ }
+
+ private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
+
+ private MethodProxy methodProxy;
+
+ public CglibMethodInvocation(Object target, Method method, Object[] objects, MethodProxy methodProxy) {
+ super(target, method, objects);
+ this.methodProxy = methodProxy;
+ }
+
+ @Override
+ public Object proceed() throws Throwable {
+ return this.methodProxy.invoke(this.target, this.arguments);
+ }
+ }
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/JdkDynamicAopProxy.java b/src/main/java/cn/abelib/springframework/aop/framework/JdkDynamicAopProxy.java
new file mode 100644
index 0000000..a9704d7
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/JdkDynamicAopProxy.java
@@ -0,0 +1,40 @@
+package cn.abelib.springframework.aop.framework;
+
+import org.aopalliance.intercept.MethodInterceptor;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/19 22:46
+ */
+public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
+
+ private final AdvisedSupport advised;
+
+ public JdkDynamicAopProxy(AdvisedSupport advised) {
+ this.advised = advised;
+ }
+
+ @Override
+ public Object getProxy() {
+ return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getTargetSource().getTargetClass(), this);
+ }
+
+ @Override
+ public Object getProxy(ClassLoader classLoader) {
+ return Proxy.newProxyInstance(classLoader, advised.getTargetSource().getTargetClass(), this);
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
+ MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
+ return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
+ }
+ return method.invoke(advised.getTargetSource().getTarget(), args);
+ }
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/ProxyFactory.java b/src/main/java/cn/abelib/springframework/aop/framework/ProxyFactory.java
new file mode 100644
index 0000000..b3b1527
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/ProxyFactory.java
@@ -0,0 +1,28 @@
+package cn.abelib.springframework.aop.framework;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/6 下午 11:43
+ */
+public class ProxyFactory {
+
+ private AdvisedSupport advisedSupport;
+
+ public ProxyFactory(AdvisedSupport advisedSupport) {
+ this.advisedSupport = advisedSupport;
+ }
+
+ public Object getProxy() {
+ return createAopProxy().getProxy();
+ }
+
+ private AopProxy createAopProxy() {
+ if (advisedSupport.isProxyTargetClass()) {
+ return new CglibAopProxy(advisedSupport);
+ }
+
+ return new JdkDynamicAopProxy(advisedSupport);
+ }
+
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/ReflectiveMethodInvocation.java b/src/main/java/cn/abelib/springframework/aop/framework/ReflectiveMethodInvocation.java
new file mode 100644
index 0000000..7b7f2fc
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/ReflectiveMethodInvocation.java
@@ -0,0 +1,45 @@
+package cn.abelib.springframework.aop.framework;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/25 23:57
+ */
+public class ReflectiveMethodInvocation implements MethodInvocation {
+
+ protected final Object target;
+
+ protected final Method method;
+
+ protected final Object[] arguments;
+
+ public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) {
+ this.target = target;
+ this.method = method;
+ this.arguments = arguments;
+ }
+
+ @Override
+ public Method getMethod() {
+ return this.method;
+ }
+
+ @Override
+ public Object[] getArguments() {
+ return this.arguments;
+ }
+
+ @Override
+ public Object proceed() throws Throwable {
+ return method.invoke(target, arguments);
+ }
+
+ @Override
+ public Object getThis() {
+ return target;
+ }
+}
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/adapter/MethodBeforeAdviceInterceptor.java b/src/main/java/cn/abelib/springframework/aop/framework/adapter/MethodBeforeAdviceInterceptor.java
new file mode 100644
index 0000000..8cf2533
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/adapter/MethodBeforeAdviceInterceptor.java
@@ -0,0 +1,33 @@
+package cn.abelib.springframework.aop.framework.adapter;
+
+import cn.abelib.springframework.aop.MethodBeforeAdvice;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:40
+ */
+public class MethodBeforeAdviceInterceptor implements MethodInterceptor {
+ private MethodBeforeAdvice advice;
+
+ public MethodBeforeAdviceInterceptor(){}
+
+ /**
+ * Create a new MethodBeforeAdviceInterceptor for the given advice.
+ */
+ public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
+ this.advice = advice;
+ }
+
+ @Override
+ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
+ this.advice.before(methodInvocation.getMethod(), methodInvocation.getArguments(), methodInvocation.getThis() );
+ return methodInvocation.proceed();
+ }
+
+ public void setAdvice(MethodBeforeAdvice advice) {
+ this.advice = advice;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/abelib/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java b/src/main/java/cn/abelib/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java
new file mode 100644
index 0000000..b424e5a
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java
@@ -0,0 +1,86 @@
+package cn.abelib.springframework.aop.framework.autoproxy;
+
+import cn.abelib.springframework.aop.Advisor;
+import cn.abelib.springframework.aop.ClassFilter;
+import cn.abelib.springframework.aop.Pointcut;
+import cn.abelib.springframework.aop.TargetSource;
+import cn.abelib.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
+import cn.abelib.springframework.aop.framework.AdvisedSupport;
+import cn.abelib.springframework.aop.framework.ProxyFactory;
+import cn.abelib.springframework.beans.BeansException;
+import cn.abelib.springframework.beans.factory.BeanFactory;
+import cn.abelib.springframework.beans.factory.BeanFactoryAware;
+import cn.abelib.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
+import cn.abelib.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.aopalliance.aop.Advice;
+import org.aopalliance.intercept.MethodInterceptor;
+
+import java.util.Collection;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:40
+ */
+public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
+
+ private DefaultListableBeanFactory beanFactory;
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = (DefaultListableBeanFactory) beanFactory;
+ }
+
+ /**
+ * @param beanClass
+ * @param beanName
+ * @return
+ * @throws BeansException
+ */
+ @Override
+ public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException {
+ if (isInfrastructureClass(beanClass)) {
+ return null;
+ }
+
+ Collection advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
+
+ for (AspectJExpressionPointcutAdvisor advisor : advisors) {
+ ClassFilter classFilter = advisor.getPointcut().getClassFilter();
+ if (!classFilter.matches(beanClass)) continue;
+
+ AdvisedSupport advisedSupport = new AdvisedSupport();
+
+ TargetSource targetSource = null;
+ try {
+ targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ advisedSupport.setTargetSource(targetSource);
+ advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
+ advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
+ advisedSupport.setProxyTargetClass(false);
+
+ return new ProxyFactory(advisedSupport).getProxy();
+ }
+
+ return null;
+ }
+
+ private boolean isInfrastructureClass(Class> beanClass) {
+ return Advice.class.isAssignableFrom(beanClass)
+ || Pointcut.class.isAssignableFrom(beanClass)
+ || Advisor.class.isAssignableFrom(beanClass);
+ }
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cn/abelib/springframework/beans/factory/AbstractAutowireCapableBeanFactory.java b/src/main/java/cn/abelib/springframework/beans/factory/AbstractAutowireCapableBeanFactory.java
index 5ea0094..bb9b9f1 100644
--- a/src/main/java/cn/abelib/springframework/beans/factory/AbstractAutowireCapableBeanFactory.java
+++ b/src/main/java/cn/abelib/springframework/beans/factory/AbstractAutowireCapableBeanFactory.java
@@ -4,6 +4,8 @@
import cn.abelib.springframework.beans.PropertyValue;
import cn.abelib.springframework.beans.PropertyValues;
import cn.abelib.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import cn.abelib.springframework.beans.factory.config.BeanDefinition;
+import cn.abelib.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import cn.abelib.springframework.beans.factory.support.AbstractBeanDefinition;
import cn.abelib.springframework.beans.factory.config.BeanPostProcessor;
import cn.abelib.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy;
@@ -29,13 +31,19 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
protected Object createBean(String beanName, AbstractBeanDefinition beanDefinition, Object[] args) throws BeansException {
Object bean;
try {
+ bean = resolveBeforeInstantiation(beanName, beanDefinition);
+ if (null != bean) {
+ return bean;
+ }
+
bean = createBeanInstance(beanDefinition, beanName, args);
applyPropertyValues(beanName, bean, beanDefinition);
// initialize Bean
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
- throw new BeansException("Instantiation of bean failed", e);
+ System.err.printf("Instantiation of bean failed: %s%n", beanName);
+ throw new BeansException(String.format("Instantiation of bean failed: %s", beanName), e);
}
// 注册实现了 DisposableBean 接口的 Bean 对象
@@ -50,6 +58,29 @@ protected Object createBean(String beanName, AbstractBeanDefinition beanDefiniti
return bean;
}
+ /**
+ * todo 缺失property
+ * Apply before-instantiation post-processors, resolving whether there is a
+ * before-instantiation shortcut for the specified bean.
+ */
+ protected Object resolveBeforeInstantiation(String beanName, AbstractBeanDefinition beanDefinition) {
+ Object bean = applyBeanPostProcessorsBeforeInstantiation(beanDefinition.getBeanClass(), beanName);
+ if (null != bean) {
+ bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
+ }
+ return bean;
+ }
+
+ protected Object applyBeanPostProcessorsBeforeInstantiation(Class> beanClass, String beanName) {
+ for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
+ if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
+ Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInstantiation(beanClass, beanName);
+ if (null != result) return result;
+ }
+ }
+ return null;
+ }
+
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, AbstractBeanDefinition beanDefinition) {
// 非Singleton Bean不处理
if (!beanDefinition.isSingleton()) {
diff --git a/src/main/java/cn/abelib/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java b/src/main/java/cn/abelib/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java
new file mode 100644
index 0000000..c1bc087
--- /dev/null
+++ b/src/main/java/cn/abelib/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java
@@ -0,0 +1,17 @@
+package cn.abelib.springframework.beans.factory.config;
+
+import cn.abelib.springframework.beans.BeansException;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/7 下午 11:00
+ */
+public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
+ /**
+ * Apply this BeanPostProcessor before the target bean gets instantiated.
+ * The returned bean object may be a proxy to use instead of the target bean,
+ * effectively suppressing default instantiation of the target bean.
+ */
+ Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException;
+}
diff --git a/src/main/java/cn/abelib/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java b/src/main/java/cn/abelib/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java
index 9d12898..e3ad981 100644
--- a/src/main/java/cn/abelib/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java
+++ b/src/main/java/cn/abelib/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java
@@ -23,7 +23,9 @@ public int hashCode() {
return super.hashCode();
}
});
- if (null == ctor) return enhancer.create();
+ if (null == ctor) {
+ return enhancer.create();
+ }
return enhancer.create(ctor.getParameterTypes(), args);
}
}
diff --git a/src/main/java/org/aopalliance/aop/Advice.java b/src/main/java/org/aopalliance/aop/Advice.java
new file mode 100644
index 0000000..d36ee72
--- /dev/null
+++ b/src/main/java/org/aopalliance/aop/Advice.java
@@ -0,0 +1,13 @@
+package org.aopalliance.aop;
+
+/**
+ *
+ * Tag interface for Advice. Implementations can be any type
+ * of advice, such as Interceptors.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/31 下午 10:31
+ */
+public interface Advice {
+}
diff --git a/src/main/java/org/aopalliance/intercept/Interceptor.java b/src/main/java/org/aopalliance/intercept/Interceptor.java
new file mode 100644
index 0000000..f7ab400
--- /dev/null
+++ b/src/main/java/org/aopalliance/intercept/Interceptor.java
@@ -0,0 +1,14 @@
+package org.aopalliance.intercept;
+
+import org.aopalliance.aop.Advice;
+
+/**
+ * This interface represents a generic interceptor.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/6 下午 11:39
+ */
+public interface Interceptor extends Advice {
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/aopalliance/intercept/Invocation.java b/src/main/java/org/aopalliance/intercept/Invocation.java
new file mode 100644
index 0000000..e3452c9
--- /dev/null
+++ b/src/main/java/org/aopalliance/intercept/Invocation.java
@@ -0,0 +1,16 @@
+package org.aopalliance.intercept;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/6 下午 7:44
+ */
+public interface Invocation extends Joinpoint {
+
+ /**
+ * Get the arguments as an array object.
+ * It is possible to change element values within this
+ */
+ Object[] getArguments();
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/aopalliance/intercept/Joinpoint.java b/src/main/java/org/aopalliance/intercept/Joinpoint.java
new file mode 100644
index 0000000..41e7be1
--- /dev/null
+++ b/src/main/java/org/aopalliance/intercept/Joinpoint.java
@@ -0,0 +1,22 @@
+package org.aopalliance.intercept;
+
+/**
+ * This interface represents a generic runtime joinpoint (in the AOP
+ * terminology).
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/6 下午 11:34
+ */
+public interface Joinpoint {
+
+ /**
+ * Proceed to the next interceptor in the chain.
+ */
+ Object proceed() throws Throwable;
+
+ /**
+ * Return the object that holds the current joinpoint's static part.
+ */
+ Object getThis();
+
+}
diff --git a/src/main/java/org/aopalliance/intercept/MethodInterceptor.java b/src/main/java/org/aopalliance/intercept/MethodInterceptor.java
new file mode 100644
index 0000000..8ee8410
--- /dev/null
+++ b/src/main/java/org/aopalliance/intercept/MethodInterceptor.java
@@ -0,0 +1,18 @@
+package org.aopalliance.intercept;
+
+/**
+ * Intercepts calls on an interface on its way to the target. These
+ * are nested "on top" of the target.
+ *
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/6 下午 11:39
+ */
+public interface MethodInterceptor extends Interceptor {
+ /**
+ * Implement this method to perform extra treatments before and
+ * after the invocation.
+ */
+ Object invoke(MethodInvocation invocation) throws Throwable;
+
+}
diff --git a/src/main/java/org/aopalliance/intercept/MethodInvocation.java b/src/main/java/org/aopalliance/intercept/MethodInvocation.java
new file mode 100644
index 0000000..121d55d
--- /dev/null
+++ b/src/main/java/org/aopalliance/intercept/MethodInvocation.java
@@ -0,0 +1,17 @@
+package org.aopalliance.intercept;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/6 下午 7:43
+ */
+public interface MethodInvocation extends Invocation {
+
+ /**
+ * Get the method being called.
+ */
+ Method getMethod();
+
+}
diff --git a/src/main/resources/spring_aop.xml b/src/main/resources/spring_aop.xml
new file mode 100644
index 0000000..44ad062
--- /dev/null
+++ b/src/main/resources/spring_aop.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/cn/abelib/springframework/HelloAopService.java b/src/test/java/cn/abelib/springframework/HelloAopService.java
new file mode 100644
index 0000000..6622eee
--- /dev/null
+++ b/src/test/java/cn/abelib/springframework/HelloAopService.java
@@ -0,0 +1,35 @@
+package cn.abelib.springframework;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/10 下午 11:30
+ */
+public class HelloAopService implements IHelloService {
+ private String name;
+
+ public HelloAopService() {}
+
+ public HelloAopService(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public void sayHello() {
+ System.out.println("Hello " + name);
+ }
+
+ @Override
+ public String hello() {
+ return "Hello " + name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/src/test/java/cn/abelib/springframework/HelloServiceAdvice.java b/src/test/java/cn/abelib/springframework/HelloServiceAdvice.java
new file mode 100644
index 0000000..54f4028
--- /dev/null
+++ b/src/test/java/cn/abelib/springframework/HelloServiceAdvice.java
@@ -0,0 +1,19 @@
+package cn.abelib.springframework;
+
+import cn.abelib.springframework.aop.MethodBeforeAdvice;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/8 下午 11:13
+ */
+public class HelloServiceAdvice implements MethodBeforeAdvice {
+ public HelloServiceAdvice() {}
+
+ @Override
+ public void before(Method method, Object[] args, Object target) throws Throwable {
+ System.out.println("Intercept method name: " + method.getName());
+ }
+}
diff --git a/src/test/java/cn/abelib/springframework/HelloServiceInterceptor.java b/src/test/java/cn/abelib/springframework/HelloServiceInterceptor.java
new file mode 100644
index 0000000..cfcc0c3
--- /dev/null
+++ b/src/test/java/cn/abelib/springframework/HelloServiceInterceptor.java
@@ -0,0 +1,27 @@
+package cn.abelib.springframework;
+
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/26 22:55
+ */
+public class HelloServiceInterceptor implements MethodInterceptor {
+
+ @Override
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ long start = System.currentTimeMillis();
+ try {
+ return invocation.proceed();
+ } finally {
+ System.out.println("AOP start");
+ System.out.println("Method Name:" + invocation.getMethod());
+ System.out.println("Spent Time:" + (System.currentTimeMillis() - start) + "ms");
+ System.out.println("AOP end\r\n");
+ }
+ }
+}
+
diff --git a/src/test/java/cn/abelib/springframework/aop/AopTest.java b/src/test/java/cn/abelib/springframework/aop/AopTest.java
new file mode 100644
index 0000000..4b09371
--- /dev/null
+++ b/src/test/java/cn/abelib/springframework/aop/AopTest.java
@@ -0,0 +1,38 @@
+package cn.abelib.springframework.aop;
+
+import cn.abelib.springframework.HelloService;
+import cn.abelib.springframework.HelloServiceInterceptor;
+import cn.abelib.springframework.IHelloService;
+import cn.abelib.springframework.aop.aspectj.AspectJExpressionPointcut;
+import cn.abelib.springframework.aop.framework.AdvisedSupport;
+import cn.abelib.springframework.aop.framework.CglibAopProxy;
+import cn.abelib.springframework.aop.framework.JdkDynamicAopProxy;
+import org.junit.Test;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/3/26 22:59
+ */
+public class AopTest {
+
+ @Test
+ public void testDynamicAop() {
+ // 目标对象
+ HelloService helloService = new HelloService("Abel");
+
+ // 组装代理信息
+ AdvisedSupport advisedSupport = new AdvisedSupport();
+ advisedSupport.setTargetSource(new TargetSource(helloService));
+ advisedSupport.setMethodInterceptor(new HelloServiceInterceptor());
+ advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* cn.abelib.springframework.IHelloService.*(..))"));
+
+ // JdkDynamicAopProxy
+ IHelloService jdkProxy = (IHelloService) new JdkDynamicAopProxy(advisedSupport).getProxy();
+ System.out.println("jdkProxy result: " + jdkProxy.hello());
+
+ // Cglib2AopProxy
+ IHelloService cglibProxy = (IHelloService) new CglibAopProxy(advisedSupport).getProxy();
+ cglibProxy.sayHello();
+ }
+}
diff --git a/src/test/java/cn/abelib/springframework/aop/SpringAopTest.java b/src/test/java/cn/abelib/springframework/aop/SpringAopTest.java
new file mode 100644
index 0000000..a198134
--- /dev/null
+++ b/src/test/java/cn/abelib/springframework/aop/SpringAopTest.java
@@ -0,0 +1,22 @@
+package cn.abelib.springframework.aop;
+
+import cn.abelib.springframework.HelloAopService;
+import cn.abelib.springframework.IHelloService;
+import cn.abelib.springframework.context.support.ClassPathXmlApplicationContext;
+import org.junit.Test;
+
+/**
+ * @author abel.huang
+ * @version 1.0
+ * @date 2024/4/8 下午 11:22
+ */
+public class SpringAopTest {
+
+ @Test
+ public void testAop() {
+ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring_aop.xml");
+ IHelloService helloService = applicationContext.getBean("helloService", HelloAopService.class);
+
+ System.out.println("result: " + helloService.hello());
+ }
+}