Spring深入理解-自己造Spring轮子-IOC理解1

Spring的主要核心是SpringIOC和SpringAOP。
SringIOC:反转控制,是类的实例化操作交给Spring去完成。
SpringAOP:切面编程,是动态代理技术的一种实现。

我的IOC:

1.每次我们写Controller的时候,我们都会在类上面使用注解Controller。
所以我们定一个注解:

@Retention(value=RetentionPolicy.RUNTIME)
@Target(value=ElementType.TYPE)
public @interface Action {	
}

2.定义注解后,我们再写一个Controller并写上注解。

@Action
public class TestAction {
	public String test() {
		return "123";
	}
}

3.这样话,我们要的结果是用我们自己的扫描器去扫描注解了Action的的类,然后实列化。并且,在程序需要的时候能够获取到。
扫描注解类

public class PackageClassScan {
	public static List<String> scan(String packageName){
		String pacakgeNameTmp = packageName.replaceAll("\\.", "/") + "/";
		//System.out.println(pacakgeNameTmp);
		String rootPath = PackageClassScan.class.getResource("/").getPath();
		System.out.println(rootPath);
		File f = new File(rootPath + pacakgeNameTmp);
		//System.out.println(f.getAbsolutePath());
		String[] classFiles = f.list();
		List<String> paths = new ArrayList<>();
		for(String fclf: classFiles) {
			//System.out.println(fclf);
			if(!new File(fclf).isDirectory()) {
				paths.add(fclf);
			}
		}
		return paths;
	}
}
  • 通过scan方法,我们可以根据传入的package,扫描package下面的class。主要是为了获取package下面的类。

主要做实列化和存储对象的类

public class ApplicationContext {
	Map<Class<?>,Object> beas  = new HashMap<>();
	public ApplicationContext(String packageName) {
		List<String> clss =  PackageClassScan.scan(packageName);
    	//判断是否有Action
		for(String clsName: clss) {
			try {
				String clsNameTmp = clsName.replace(".class", "");
				Class<?> cls = Class.forName(packageName + "." +clsNameTmp);
				addActionBeans(cls);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}	
	private void addActionBeans(Class<?> cls) throws InstantiationException, IllegalAccessException {
		Action annotion = cls.getAnnotation(Action.class);
		if(annotion != null)
			addBeas(cls);
	}
	public <T> T getBeans(Class<T> cls){
		return (T)beas.get(cls);
	}
	public void addBeans(Class<?> cls,Object o) {
		beas.put(cls, o);
	}
	public void addBeas(Class<?> cls) throws InstantiationException, IllegalAccessException {
		beas.put(cls, cls.newInstance());
	}
	
}
  • 构造方法,做了扫描package下面的类操作。
  • addActionBeans方法判断了是否又Action注解。又注解就将该类实例化然后放置IOC容器中保存。
  • getBeans在程序又需要的时候,通过该方法获取到对应的Bean,填充。

3.Main方法

public class App {
    public static void main( String[] args ){   
    	String packageName = "com.aming.novel.controller";
    	ApplicationContext context = new ApplicationContext(packageName);
    	System.out.println(context.getBeans(TestAction.class));
    }
}

Spring的实现

1.Spring的扫描
我们可以随便新建一个包:com.aming.action
在这里插入图片描述
然后在包里面添加俩个类
在这里插入图片描述
写一个main方法开始跟踪看看Spring是怎么扫描的。

public static void main( String[] args )
    {
      ApplicationContext a = new AnnotationConfigApplicationContext(new String[] {"com.aming.action"});
    }
  • 首先
public AnnotationConfigApplicationContext(String... basePackages) {
   	this();
   	scan(basePackages);
   	refresh();
   }

很明显是通过scan方法,我们再点进去

public void scan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		this.scanner.scan(basePackages);
	}

这里调用了 this.scanner.can(“com.aming.action”)
我们这里打下断点使用debug调试进入

	public int scan(String... basePackages) {
		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

		doScan(basePackages);

		// Register annotation config processors, if necessary.
		if (this.includeAnnotationConfig) {
			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
		}

		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
	}

这里调用了doScan方法,打断点继续调试

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

注意Set candidates = findCandidateComponents(basePackage);

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
		try {
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + "/" + this.resourcePattern;
			Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
						MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
						if (isCandidateComponent(metadataReader)) {
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

跟着:Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);

	@Override
	public Resource[] getResources(String locationPattern) throws IOException {
		if (this.resourceLoader instanceof ResourcePatternResolver) {
			return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern);
		}
		return super.getResources(locationPattern);
	}

接着:return super.getResources(locationPattern);

public Resource[] getResources(String locationPattern) throws IOException {
		return this.resourcePatternResolver.getResources(locationPattern);
	}

接着:return this.resourcePatternResolver.getResources(locationPattern);

public Resource[] getResources(String locationPattern) throws IOException {
		Assert.notNull(locationPattern, "Location pattern must not be null");
		if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
			// a class path resource (multiple resources for same name possible)
			if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
				// a class path resource pattern
				return findPathMatchingResources(locationPattern);
			}
			else {
				// all class path resources with the given name
				return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
			}
		}
		else {
			// Only look for a pattern after a prefix here
			// (to not get fooled by a pattern symbol in a strange prefix).
			int prefixEnd = locationPattern.indexOf(":") + 1;
			if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
				// a file pattern
				return findPathMatchingResources(locationPattern);
			}
			else {
				// a single resource with the given name
				return new Resource[] {getResourceLoader().getResource(locationPattern)};
			}
		}
	}

接着:return findPathMatchingResources(locationPattern);

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
		String rootDirPath = determineRootDir(locationPattern);
		String subPattern = locationPattern.substring(rootDirPath.length());
		Resource[] rootDirResources = getResources(rootDirPath);
		Set<Resource> result = new LinkedHashSet<Resource>(16);
		for (Resource rootDirResource : rootDirResources) {
			rootDirResource = resolveRootDirResource(rootDirResource);
			if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
				result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
			}
			else if (isJarResource(rootDirResource)) {
				result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
			}
			else {
				result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
			}
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
		}
		return result.toArray(new Resource[result.size()]);
	}

注意:result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));

protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
			throws IOException {

		File rootDir;
		try {
			rootDir = rootDirResource.getFile().getAbsoluteFile();
		}
		catch (IOException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Cannot search for matching files underneath " + rootDirResource +
						" because it does not correspond to a directory in the file system", ex);
			}
			return Collections.emptySet();
		}
		return doFindMatchingFileSystemResources(rootDir, subPattern);
	}
	```
	注意:return doFindMatchingFileSystemResources(rootDir, subPattern);
	```java
	protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");
		}
		Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
		Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());
		for (File file : matchingFiles) {
			result.add(new FileSystemResource(file));
		}
		return result;
	}

到这里就将我们那里com.aming.action下面的类包装成FileSystemResource返回。
然后我们回到findCandidateComponents

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值