forked from code4craft/tiny-spring
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of github.com:code4craft/tiny-spring
- Loading branch information
Showing
69 changed files
with
2,140 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.ysj.tinySpring; | ||
|
||
/** | ||
* 用于代表property标签的ref属性里的对象 | ||
* | ||
*/ | ||
public class BeanReference { | ||
|
||
public String name; | ||
|
||
public Object bean; | ||
|
||
public BeanReference(String name){ | ||
this.name = name; | ||
} | ||
|
||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
public Object getBean() { | ||
return bean; | ||
} | ||
|
||
public void setBean(Object bean) { | ||
this.bean = bean; | ||
} | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
src+/main/java/com/ysj/tinySpring/aop/AbstractAopProxy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.ysj.tinySpring.aop; | ||
|
||
/** | ||
* 继承了AopProxy接口,有获取代理对象的能力 | ||
* 同时继承此接口有AdvisedSupport的支持 | ||
* | ||
*/ | ||
public abstract class AbstractAopProxy implements AopProxy{ | ||
|
||
protected AdvisedSupport advised; | ||
|
||
public AbstractAopProxy(AdvisedSupport advised) { | ||
this.advised = advised; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.ysj.tinySpring.aop; | ||
|
||
import org.aopalliance.intercept.MethodInterceptor; | ||
|
||
/** | ||
* AdvisedSupport封装了TargetSource, MethodInterceptor和MethodMatcher | ||
* | ||
*/ | ||
public class AdvisedSupport { | ||
|
||
// 要拦截的对象 | ||
private TargetSource targetSource; | ||
|
||
/** | ||
* 方法拦截器 | ||
* Spring的AOP只支持方法级别的调用,所以其实在AopProxy里,我们只需要将MethodInterceptor放入对象的方法调用 | ||
*/ | ||
private MethodInterceptor methodInterceptor; | ||
|
||
// 方法匹配器,判断是否是需要拦截的方法 | ||
private MethodMatcher methodMatcher; | ||
|
||
|
||
|
||
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.ysj.tinySpring.aop; | ||
|
||
import org.aopalliance.aop.Advice; | ||
|
||
/** | ||
* 通知器 | ||
* 用于实现 具体的方法拦截,需要使用者编写,也就对应了 Spring 中的前置通知、后置通知、环切通知等。 | ||
* | ||
*/ | ||
public interface Advisor { | ||
|
||
/** | ||
* 获取通知器(方法拦截器) | ||
* @return | ||
*/ | ||
Advice getAdvice(); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.ysj.tinySpring.aop; | ||
|
||
/** | ||
* AopProxy是个标志型接口 | ||
* 暴露获取aop代理对象方法的接口 | ||
* | ||
*/ | ||
public interface AopProxy { | ||
|
||
/** | ||
* 获取代理对象 | ||
* @return | ||
*/ | ||
Object getProxy(); | ||
|
||
} |
52 changes: 52 additions & 0 deletions
52
src+/main/java/com/ysj/tinySpring/aop/AspectJAroundAdvice.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.ysj.tinySpring.aop; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
import org.aopalliance.aop.Advice; | ||
import org.aopalliance.intercept.MethodInterceptor; | ||
import org.aopalliance.intercept.MethodInvocation; | ||
|
||
import com.ysj.tinySpring.beans.factory.BeanFactory; | ||
|
||
/** | ||
* 环绕通知 | ||
* 用AspectJ表达式匹配 | ||
* | ||
*/ | ||
public class AspectJAroundAdvice implements Advice, MethodInterceptor { | ||
|
||
private BeanFactory beanFactory; | ||
|
||
private Method aspectJAdviceMethod; | ||
|
||
private String aspectInstanceName; | ||
|
||
@Override | ||
public Object invoke(MethodInvocation invocation) throws Throwable { | ||
return aspectJAdviceMethod.invoke(beanFactory.getBean(aspectInstanceName), invocation); | ||
} | ||
|
||
public BeanFactory getBeanFactory() { | ||
return beanFactory; | ||
} | ||
|
||
public void setBeanFactory(BeanFactory beanFactory) { | ||
this.beanFactory = beanFactory; | ||
} | ||
|
||
public Method getAspectJAdviceMethod() { | ||
return aspectJAdviceMethod; | ||
} | ||
|
||
public void setAspectJAdviceMethod(Method aspectJAdviceMethod) { | ||
this.aspectJAdviceMethod = aspectJAdviceMethod; | ||
} | ||
|
||
public String getAspectInstanceName() { | ||
return aspectInstanceName; | ||
} | ||
|
||
public void setAspectInstanceName(String aspectInstanceName) { | ||
this.aspectInstanceName = aspectInstanceName; | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
src+/main/java/com/ysj/tinySpring/aop/AspectJAwareAdvisorAutoProxyCreator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package com.ysj.tinySpring.aop; | ||
|
||
import java.util.List; | ||
|
||
import org.aopalliance.intercept.MethodInterceptor; | ||
|
||
import com.ysj.tinySpring.beans.BeanPostProcessor; | ||
import com.ysj.tinySpring.beans.factory.AbstractBeanFactory; | ||
import com.ysj.tinySpring.beans.factory.BeanFactory; | ||
|
||
/** | ||
* 实现了BeanFactoryAware接口:这个接口提供了对 BeanFactory 的感知,这样,尽管它是容器中的一个 Bean,却 | ||
* 可以获取容器 的引用,进而获取容器中所有的切点对象,决定对哪些对象的哪些方法进行代理。解决了 为哪些对象 | ||
* 提供 AOP 的植入 的问题。 | ||
* | ||
*/ | ||
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware { | ||
|
||
private AbstractBeanFactory beanFactory; | ||
|
||
@Override | ||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception { | ||
return bean; | ||
} | ||
|
||
/** | ||
* 可以取看看AbstractBeanFactory的getBean()的实现 | ||
* bean实例化后要进行初始化操作,会经过这个方法满足条件则生成相关的代理类并返回 | ||
*/ | ||
@Override | ||
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { | ||
// 如果是切点通知器,则直接返回 | ||
if (bean instanceof AspectJExpressionPointcutAdvisor) { | ||
return bean; | ||
} | ||
// 如果bean是方法拦截器,则直接返回 | ||
if (bean instanceof MethodInterceptor) { | ||
return bean; | ||
} | ||
// 通过getBeansForType方法加载BeanFactory 中所有的 PointcutAdvisor(保证了 PointcutAdvisor 的实例化顺序优于普通 Bean。) | ||
// AspectJ方式实现织入,这里它会扫描所有Pointcut,并对bean做织入。 | ||
List<AspectJExpressionPointcutAdvisor> advisors = beanFactory | ||
.getBeansForType(AspectJExpressionPointcutAdvisor.class); | ||
for (AspectJExpressionPointcutAdvisor advisor : advisors) { | ||
// 匹配要拦截的类 | ||
// 使用AspectJExpressionPointcut的matches匹配器,判断当前对象是不是要拦截的类的对象。 | ||
if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) { | ||
// ProxyFactory继承了AdvisedSupport,所以内部封装了TargetSource和MethodInterceptor的元数据对象 | ||
ProxyFactory advisedSupport = new ProxyFactory(); | ||
// 设置切点的方法拦截器 | ||
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); | ||
// 设置切点的方法匹配器 | ||
// 利用AspectJ表达式进行方法匹配 | ||
// AspectJExpressionPointcutAdvisor里的AspectJExpressionPointcut的getMethodMatcher()方法 | ||
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher()); | ||
// 是要拦截的类, 生成一个 TargetSource(要拦截的对象和其类型)(被代理对象) | ||
TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces()); | ||
advisedSupport.setTargetSource(targetSource); | ||
// 交给实现了 AopProxy接口的getProxy方法的ProxyFactory去生成代理对象 | ||
return advisedSupport.getProxy(); | ||
} | ||
} | ||
return bean; | ||
} | ||
|
||
@Override | ||
public void setBeanFactory(BeanFactory beanFactory) throws Exception { | ||
this.beanFactory = (AbstractBeanFactory) beanFactory; | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
src+/main/java/com/ysj/tinySpring/aop/AspectJExpressionPointcut.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package com.ysj.tinySpring.aop; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import org.aspectj.weaver.tools.PointcutExpression; | ||
import org.aspectj.weaver.tools.PointcutParser; | ||
import org.aspectj.weaver.tools.PointcutPrimitive; | ||
import org.aspectj.weaver.tools.ShadowMatch; | ||
|
||
/** | ||
* 通过AspectJ表达式识别切点 | ||
* | ||
*/ | ||
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher { | ||
|
||
private PointcutParser pointcutParser; | ||
|
||
private String expression; | ||
|
||
private PointcutExpression pointcutExpression; | ||
|
||
private static final Set<PointcutPrimitive> DEFAULT_SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>(); | ||
|
||
static { | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS); | ||
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET); | ||
} | ||
|
||
public AspectJExpressionPointcut() { | ||
this(DEFAULT_SUPPORTED_PRIMITIVES); | ||
} | ||
|
||
public AspectJExpressionPointcut(Set<PointcutPrimitive> supportedPrimitives) { | ||
pointcutParser = PointcutParser | ||
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives); | ||
} | ||
|
||
protected void checkReadyToMatch() { | ||
if (pointcutExpression == null) { | ||
pointcutExpression = buildPointcutExpression(); | ||
} | ||
} | ||
|
||
private PointcutExpression buildPointcutExpression() { | ||
return pointcutParser.parsePointcutExpression(expression); | ||
} | ||
|
||
public void setExpression(String expression) { | ||
this.expression = expression; | ||
} | ||
|
||
@Override | ||
public ClassFilter getClassFilter() { | ||
return this; | ||
} | ||
|
||
@Override | ||
public MethodMatcher getMethodMatcher() { | ||
return this; | ||
} | ||
|
||
@Override | ||
public boolean matches(Class targetClass) { | ||
checkReadyToMatch(); | ||
return pointcutExpression.couldMatchJoinPointsInType(targetClass); | ||
} | ||
|
||
@Override | ||
public boolean matches(Method method, Class targetClass) { | ||
checkReadyToMatch(); | ||
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method); | ||
if (shadowMatch.alwaysMatches()) { | ||
return true; | ||
} else if (shadowMatch.neverMatches()) { | ||
return false; | ||
} | ||
// TODO:其他情况不判断了!见org.springframework.aop.aspectj.RuntimeTestWalker | ||
return false; | ||
} | ||
|
||
} |
Oops, something went wrong.