Skip to content

Commit

Permalink
Merge branch 'master' of github.com:code4craft/tiny-spring
Browse files Browse the repository at this point in the history
  • Loading branch information
code4craft committed Feb 12, 2018
2 parents 642a173 + 24493cd commit 2e0a2ba
Show file tree
Hide file tree
Showing 69 changed files with 2,140 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ tiny-spring

`tiny-spring`是为了学习Spring的而开发的,可以认为是一个Spring的精简版。Spring的代码很多,层次复杂,阅读起来费劲。我尝试从使用功能的角度出发,参考Spring的实现,一步一步构建,最终完成一个精简版的Spring。有人把程序员与画家做比较,画家有门基本功叫临摹,tiny-spring可以算是一个程序的临摹版本-从自己的需求出发,进行程序设计,同时对著名项目进行参考。

[点此查看](https://www.zybuluo.com/dugu9sword/note/382745)对本项目的类文件结构和逻辑的分析。 (by @dugu9sword)

## 功能

1. 支持singleton类型的bean,包括初始化、属性注入、以及依赖bean注入。
Expand Down
34 changes: 34 additions & 0 deletions src+/main/java/com/ysj/tinySpring/BeanReference.java
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 src+/main/java/com/ysj/tinySpring/aop/AbstractAopProxy.java
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;
}

}
48 changes: 48 additions & 0 deletions src+/main/java/com/ysj/tinySpring/aop/AdvisedSupport.java
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;
}
}
18 changes: 18 additions & 0 deletions src+/main/java/com/ysj/tinySpring/aop/Advisor.java
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();

}
16 changes: 16 additions & 0 deletions src+/main/java/com/ysj/tinySpring/aop/AopProxy.java
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 src+/main/java/com/ysj/tinySpring/aop/AspectJAroundAdvice.java
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;
}
}
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;
}
}
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;
}

}
Loading

0 comments on commit 2e0a2ba

Please sign in to comment.