Giter Site home page Giter Site logo

tiny-spring's Introduction

tiny-spring

A tiny IoC container refer to Spring.

关于

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

点此查看对本项目的类文件结构和逻辑的分析。 (by @dugu9sword)

功能

  1. 支持singleton类型的bean,包括初始化、属性注入、以及依赖bean注入。
  2. 可从xml中读取配置。
  3. 可以使用Aspectj的方式进行AOP编写,支持接口和类代理。

使用

tiny-spring是逐步进行构建的,里程碑版本我都使用了git tag来管理。例如,最开始的tag是step-1-container-register-and-get,那么可以使用

git checkout step-1-container-register-and-get

来获得这一版本。版本历史见changelog.md

Bitdeli Badge

下面是推广

如果觉得代码理解有难度的,可以报名@方老司 的视频教程:

60分钟徒手撸出Spring框架:土法造炮篇

60分钟徒手撸出Spring框架:高仿版

tiny-spring's People

Contributors

bitdeli-chef avatar code4craft avatar dugu9sword avatar yusijia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tiny-spring's Issues

AutoProxyCreator类中对多个Advisor增强没有遍历

AutoProxyCreator类,源码41行,return advisedSupport.getProxy();
初次匹配生成动态代理之后直接返回了,无法支持多个Advisor增强;
为便于拓展,应改为:
bean=advisedSupport.getProxy();

step-9-auto-create-aop-proxy的JDK切面无效,非常困惑!!!

us.codecraft.tinyioc.context.ApplicationContextTest#test 该方法无切面效果,运行直接为:
Hello World!

而step-10-invite-cglib-and-aopproxy-factory例子就可以,反复对比源码,发现就是因为AbstractBeanFactory类中:

@OverRide
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
if (bean == null) {
bean = doCreateBean(beanDefinition);
bean = initializeBean(bean, name);
beanDefinition.setBean(bean); //本行在起作用,必须有,否则切面无效果但到底为何?
}
return bean;
}

XmlBeanDefinitionReader报错空指针

您好:你的step4中的XmlBeanDefinitionReader.processProperty(Element element, BeanDefinition beanDefinition)方法在beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name,value))步骤会报空指针,原因是传递进来的beanDefinition在上个方法中只是new出来的 BeanDefinition beanDefinition = new BeanDefinition(),所以beanDefinition.getPropertyValues()其实是null,在addPropertyValue的时候会报空指针~

Cglib2AopProxy非空判断

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		if (advised.getMethodMatcher() == null
				|| advised.getMethodMatcher().matches(method, advised.getTargetSource().getTargetClass())) {//这个地方是应该作非空判断的吧?
			return delegateMethodInterceptor.invoke(new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy));
		}
		return new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy).proceed();
	}
}

Security Vulnerability - Action Required: XXE vulnerability in the newest version of the tiny-spring

I think your project may be vulnerable to Improper Restriction of XML External Entity Reference. It shares similarities to a recent CVE disclosure CVE-2021-3869 in the project stanfordnlp/CoreNLP. The vulnerable methods are as follows:

  1. com.ysj.tinySpring.beans.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputStream inputStream) in the file src+/main/java/com/ysj/tinySpring/beans/xml/XmlBeanDefinitionReader.java
  2. us.codecraft.tinyioc.beans.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputStream inputStream) in the file src/main/java/us/codecraft/tinyioc/beans/xml/XmlBeanDefinitionReader.java

The source vulnerability information is as follows:

Vulnerability Detail:
CVE Identifier: CVE-2021-3869
Description: corenlp is vulnerable to Improper Restriction of XML External Entity Reference
Reference:https://nvd.nist.gov/vuln/detail/CVE-2021-3869
Patch: stanfordnlp/CoreNLP@5d83f1e

Vulnerability Description:
This vulnerability occurs because of the Improper Restriction of XML External Entity Reference. Given that the XML schema files which is compromised by a hacker, the victim conducts regular process may result in an XML External Entity (XXE) Injection attack.

Recommended Actions:
The corresponding fixes are similar to CVE-2021-3869 to some extent. I have provided the following fixes by applying several patching statements, ensuring that the external entities and DTDs are not loaded when parsing and processing XML documents using the document builder. You can call the function safeDocumentBuilderFactory I defined below instead of directly calling DocumentBuilderFactory.newInstance() to create a DocumentBuilderFactory object to avoid XXE attacks.

  public static DocumentBuilderFactory safeDocumentBuilderFactory() {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
      dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
      dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
      dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
      dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
      dbf.setFeature("http://apache.org/xml/features/dom/create-entity-ref-nodes", false);
      dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    } catch (ParserConfigurationException e) {
      log.warn(e);
    }
    return dbf;
  }

Considering the potential riskes it may have, I am willing to cooperate with your to verify, address, and report the identified vulnerability promptly through responsible means. If you require any further information or assistance, please do not hesitate to reach out to me.
Thank you and looking forward to hearing from you soon.

step8测试方法有点问题

testClassFilter()这个测试方法不论expression给什么包,都能匹配到类。
testMethodInterceptor()我自己写的版本无法匹配到方法

Sring循环依赖的三种情况

Spring中一个bean依赖于另一个bean的时候,可以通过构造器注入或setter注入,其中setter注入又可以分为单例和多例(prototype)。
1.如果是构造注入或多例模式的setter注入的时候,循环依赖是解决不了的;
2.如果是单例setter注入则可以解决掉循环依赖问题。原因在于Spring是先将Bean对象实例化之后再设置对象属性的而不是一次性将bean对象连同属性一起构造的。

关于step7的接口newProxyInstance()参数问题

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) {
        Objects.requireNonNull(h);

        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();

        /*
         * Look up or generate the designated proxy class and its constructor.
         */
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);

        return newProxyInstance(caller, cons, h);
    }

第二个传入的参数应该是接口,需重新定义个接口,让HelloWorldService实现
return Proxy.newProxyInstance(getClass().getClassLoader(), adviceSupport.getTargetSource().getTargetClass().getInterfaces() , this);

反射获取set方法失败

调用

Method declaredMethod = bean.getClass().getDeclaredMethod(
		"set" + propertyValue.getName().substring(0, 1).toUpperCase()
				+ propertyValue.getName().substring(1), value.getClass());

抛出异常

java.lang.NoSuchMethodException: us.codecraft.tinyioc.HelloWorldServiceImpl.setOutputService(us.codecraft.tinyioc.OutputServiceImpl)

但是HelloWorldServiceImpl有这个set方法

package us.codecraft.tinyioc;

/**
 * @author [email protected]
 */
public class HelloWorldServiceImpl implements HelloWorldService {

    private String text;

    private OutputService outputService;

    @Override
    public void helloWorld() {
        outputService.output(text);
    }

    public void setText(String text) {
        this.text = text;
    }

    public void setOutputService(OutputService outputService) {
        this.outputService = outputService;
    }

    public OutputService getOutputService() {
        return outputService;
    }
}

IOC部分补充

写个很棒,赞👍。要是IOC的部分可以结合写java的注解来个整合就更好了

step9循环依赖的问题

AbstractBeanFactory类中:
@OverRide
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
if (bean == null) {
bean = doCreateBean(beanDefinition);
bean = initializeBean(bean, name);
beanDefinition.setBean(bean);
}
return bean;
}

beanDefinition.setBean(bean);上面这行代码在原代码中没有这一行导致生成的对象非代理对象,aop不生效。但是加上之后循环引用有个问题。
A B两个类相互引用
假如AB 按顺序加载 那么调用的方法步骤为
A ->doCreateBean(beanDefinition);
B ->doCreateBean(beanDefinition);
B.setA(A) //此A为提前暴露在beanDefinitionMap中的A
B ->initializeBean(bean, name);
A.setB(B); //此时B为jdk生成的动态代理对象。
A ->initializeBean(bean, name);

以上步骤执行完成之后,A中的B是代理对象,但是B中的A还是提前暴露的对象,并没有更新成代理对象。这样的话引用就不一致了。不知道有什么办法可以解决这个问题吗。

关于 IOC 中产生的对象 的一些疑惑.

作者你好. 在学习该项目的期间, 我发现创建的 bean 都是直接被缓存在了 bean definition 中, 需要的时候也从里面获取. 也就是说, 一个类型的 bean 只会被创建一次, 所有的 bean 默认都是 spring 的 singleton ? 那如果我想提供 prototype 这个属性, 用来支持每次创建一个新的 bean. 一种可行的做法是不是新引入一个类, override `getBean()` 方法, 每次都根据相应的 bean definition 新创建一个实例就可以了?

step4有点问题

作者用来做测试用的类HelloWorldService里面只有简单的一个字段String text;这时候从tinyioc.xml中解析后的属性为字符串型,利用反射将解析后的tinyioc.xml中的属性”text“属性注入是没问题的,但是如果我用来做测试的类有其他类型的成员变量,比如我要测试的对象是User,有一个类型为Integer的age成员变量,这时候从xml解析出来的属性由于全都是String型,用反射向User中的age注入属性会报java.lang.IllegalArgumentException类型转换异常。
反正总结起来的问题就是作者测试用的类只能注入String类型的字段,其他类型好像注入不了。

AOP + 循环引用

在 step_9 的例子中,如果outputService 和 HelloWorldService 循环引用,事务应该是不生效的,这块儿有好的解决办法吗?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.