v1版本
目录结构
类图
注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PABLO_Autowired {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PABLO_Controller {
String value() default "";
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PABLO_RequestMapping {
String value() default "";
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PABLO_RequestParam {
String value() default "";
boolean required() default true;
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PABLO_Service {
String value() default "";
}
package com.gator.spring.framework.context;
import com.gator.spring.framework.annotation.PABLO_Autowired;
import com.gator.spring.framework.annotation.PABLO_Controller;
import com.gator.spring.framework.annotation.PABLO_Service;
import com.gator.spring.framework.beans.PABLO_BeanFactory;
import com.gator.spring.framework.beans.PABLO_BeanWrapper;
import com.gator.spring.framework.beans.config.PABLO_BeanPostProcessor;
import com.gator.spring.framework.beans.factory.config.PABLO_BeanDefinition;
import com.gator.spring.framework.beans.support.PABLO_BeanDefinitionReader;
import com.gator.spring.framework.beans.support.PABLO_DefaultListableBeanFactory;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Authror PABLO
* @Date 2022/5/7 11:25
* @Desc 继承默认的IOC容器
*/
public class PABLO_ApplicationContext
extends PABLO_DefaultListableBeanFactory{
private String[] configLocations;
//封装definition规范方法
private PABLO_BeanDefinitionReader reader;
//单例的IOC容器缓存
private Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();
//通用的IOC容器 缓存wrapper
private Map<String, PABLO_BeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<String, PABLO_BeanWrapper>();
public PABLO_ApplicationContext(String... configLocations) {
this.configLocations = configLocations;
try {
refresh();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void refresh() throws Exception {
//定位配置文件
reader = new PABLO_BeanDefinitionReader(this.configLocations);
//扫描加载代内存的类,封装为definition规范
List<PABLO_BeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
//注册 将配置信息注册到beanDefinitionMap中
doRegisterBeanDefinition(beanDefinitions);
//将非延迟加载的类,提前初始化
doAutowired();
System.out.println(singletonObjects);
}
private void doAutowired() {
for (Map.Entry<String, PABLO_BeanDefinition> beanDefinitionEntry : super.beanDefinitionMap.entrySet()) {
//beanFactory中的name,默认首字母小写
String beanName = beanDefinitionEntry.getKey();
//非懒加载直接getBean
if (!beanDefinitionEntry.getValue().isLazyInit()) {
try {
getBean(beanName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private void doRegisterBeanDefinition(List<PABLO_BeanDefinition> beanDefinitions) throws Exception {
for (PABLO_BeanDefinition beanDefinition : beanDefinitions) {
if (super.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())) {
throw new Exception("The “" + beanDefinition.getFactoryBeanName() + "” is exists!!");
}
super.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(), beanDefinition);
}
}
/**
* @Description: 通过class获取对象
* @Author: PABLO
* @Date: 2022/5/7 20:38
* @Params: [clazz]
* @Return: java.lang.Object
**/
public Object getBean(Class clazz) throws Exception {
return getBean(clazz.getName());
}
/**
* @Description: 根据beanName实例化并初始化对象
* @Author: PABLO
* @Date: 2022/5/7 17:27
* @Params: [beanName 支持类的完全限定名 和 首字母小写类名]
* @Return: java.lang.Object
**/
@Override
public Object getBean(String beanName) throws Exception {
//先考虑只有单例
//存在直接拿
if (this.singletonObjects.containsKey(beanName)) {
return this.singletonObjects.get(beanName);
}
//1.实例化
//获取对象的描述信息
PABLO_BeanDefinition pablo_beanDefinition = beanDefinitionMap.get(beanName);
//根据名称和对应的描述信息实例化bean
Object instance = instantiateBean(beanName, pablo_beanDefinition);
//将对象封装到beanWrapper中
PABLO_BeanWrapper beanWrapper = new PABLO_BeanWrapper(instance);
//存储IOC容器
factoryBeanInstanceCache.put(beanName, beanWrapper);
//--------------------------------------------------------------------------
//增强器
PABLO_BeanPostProcessor postProcessor = new PABLO_BeanPostProcessor();
//前置增强器
postProcessor.postProcessBeforeInitialization(instance, beanName);
//初始化
populateBean(beanName, new PABLO_BeanDefinition(), beanWrapper);
//后置增强器
postProcessor.postProcessAfterInitialization(instance, beanName);
return this.factoryBeanInstanceCache.get(beanName).getWrappedInstance();
}
private void populateBean(String beanName, PABLO_BeanDefinition pablo_beanDefinition, PABLO_BeanWrapper beanWrapper) {
Object instance = beanWrapper.getWrappedInstance();
//获得实例对象的类 class com.gator.spring.executor.service.impl.xxxClass
Class<?> clazz = beanWrapper.getWrappedClass();
//判断只有加了注解的类,才执行依赖注入
if (!(clazz.isAnnotationPresent(PABLO_Controller.class) || clazz.isAnnotationPresent(PABLO_Service.class)))
return;
//获得所有的fields
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//没有注入注解跳过
if (!field.isAnnotationPresent(PABLO_Autowired.class)) continue;
PABLO_Autowired autowired = field.getAnnotation(PABLO_Autowired.class);
//获取注解上的value值
String autowiredBeanName = autowired.value().trim();
//“”默认类型名字
if ("".equals(autowiredBeanName)) autowiredBeanName = field.getType().getName();
//强制访问
field.setAccessible(true);
try {
if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) {
continue;
}
//属性注入
field.set(instance, this.factoryBeanInstanceCache.get(autowiredBeanName).getWrappedInstance());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
//beanName可能是小写名,也可能是全路径
private Object instantiateBean(String beanName, PABLO_BeanDefinition pablo_beanDefinition) {
Object instance = null;
try {
//获取该类完全限定名
String className = pablo_beanDefinition.getBeanClassName();
//反射创建
Class<?> clazz = Class.forName(className);
instance = clazz.newInstance();
//this.singletonObjects.put(className, instance);
//实现通过完全限定名和类名小写都能获取到对象
this.singletonObjects.put(beanName, instance);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
}
package com.gator.spring.framework.beans.support;
import com.gator.spring.framework.beans.PABLO_BeanFactory;
import com.gator.spring.framework.beans.factory.config.PABLO_BeanDefinition;
import com.gator.spring.framework.context.support.PABLO_AbstractApplicationContext;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author PABLO
* @Date 2022/5/7 11:36
* @Desc IOC容器的默认实现 兜底
*/
public class PABLO_DefaultListableBeanFactory
extends PABLO_AbstractApplicationContext
implements PABLO_BeanFactory{
//存储对象描述信息map集合
//key为对象在BeanFactory中的名称,默认小写字母开头
public final Map<String, PABLO_BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, PABLO_BeanDefinition>(256);
@Override
public Object getBean(String beanName) throws Exception {
return null;
}
}
package com.gator.spring.framework.context.support;
/**
* @Author PABLO
* @Date 2022/5/7 11:30
* @Desc IOC容器的顶层设计
*/
public abstract class PABLO_AbstractApplicationContext {
/**
* @Description: 模板方法,供子类重写生效 可一键重启
* @Author: PABLO
* @Date: 2022/5/7 11:32
* @Params:
* @Return:
**/
protected void refresh() throws Exception {}
}
package com.gator.spring.framework.beans;
/**
* @Authror PABLO
* @Date 2022/5/7 11:21
* @Desc 单例工厂的顶层设计
*/
public interface PABLO_BeanFactory {
/**
* @Description: 根据beanName获取对象
* @Author: PABLO
* @Date: 2022/5/7 11:23
* @Params: [beanName]
* @Return: java.lang.Object
**/
Object getBean(String beanName) throws Exception;
}
package com.gator.spring.framework.beans.config;
/**
* @Author PABLO
* @Date 2022/5/7 13:13
* @Desc bean初始化增强器
*/
public class PABLO_BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
System.out.println( "-----"+beanName+"初始化对象之前");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
System.out.println( "-----"+beanName+"初始化对象之后");
return bean;
}
}
package com.gator.spring.framework.beans.factory.config;
import lombok.Data;
/**
* @Author PABLO
* @Date 2022/5/7 11:45
* @Desc bean描述,存储配置信息
*/
@Data
public class PABLO_BeanDefinition {
private String beanClassName; //类的完全限定名
private String factoryBeanName; //对象正在工厂内的名称,默认首字母小写
private boolean lazyInit = false;
}
package com.gator.spring.framework.beans.support;
import com.gator.spring.framework.beans.factory.config.PABLO_BeanDefinition;
import com.sun.deploy.security.BadCertificateDialog;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* @Author PABLO
* @Date 2022/5/7 12:19
* @Desc definition读取器
*/
public class PABLO_BeanDefinitionReader {
//保存所有需要注册的class
private List<String> registryBeanClasses = new ArrayList<String>();
private Properties config = new Properties();
//固定配置文件中的key,相对于xml的规范
private final String SCAN_PACKAGE = "scanPackage";
/**
* @Description: 将入参配置文件加载到内存
* @Author: PABLO
* @Date: 2022/5/7 12:21
* @Params: [locations]
* @Return:
**/
public PABLO_BeanDefinitionReader(String... locations) {
//通过URL定位找到其所对应的文件,然后转换为文件流
InputStream is = this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath:", ""));
try {
//加载配置
config.load(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//多路径扫描
String property = config.getProperty(SCAN_PACKAGE);
for (String scanPackage : property.split(",")) {
doScanner(scanPackage);
}
}
private void doScanner(String scanPackage) {
//转换为文件路径,实际上就是把.替换为/就OK了
//处理每个包,将包路径转为文件路径 .-->/
URL url = this.getClass()./*getClassLoader().*/getResource("/" + scanPackage.replaceAll("\\.", "/"));
System.out.println("url" + url);
File dir = new File(url.getFile());
for (File file : dir.listFiles()) {
//如果是文件夹,继续递归
if (file.isDirectory()) {
doScanner(scanPackage + "." + file.getName());
} else {
//E:\IDEALocation\giant-gator\target\classes\com\bj\summary\spring_mvc\controller\TestController.class
registryBeanClasses.add(scanPackage + "." + file.getName().replace(".class", "").trim());
}
}
}
public Properties getConfig() {
return this.config;
}
/**
* @Description: 配置信息封装为definition规范
* 注意:我这里定义的规则是:(可自定义)
* 如果是实现类,可使用实现类完全限定名/实现类首字母小写/接口完全限定名/
* 如果是普通类,可使用类的完全限定名/类名小写getBean获取对象
* @Author: PABLO
* @Date: 2022/5/7 12:29
* @Params: []
* @Return: java.util.List<GPBeanDefinition>
**/
public List<PABLO_BeanDefinition> loadBeanDefinitions() {
List<PABLO_BeanDefinition> result = new ArrayList<PABLO_BeanDefinition>();
try {
for (String className : registryBeanClasses) {
Class<?> beanClass = Class.forName(className);
//如遇接口使用其实现类初始化
if (beanClass.isInterface()) continue;
//beanName有三种情况:
//1、默认是类名首字母小写
//2、自定义名字
//3、接口注入
//判断首字母大小写,如小写直接添加,如大写需转换
//beanClass.getSimpleName()是类名
//beanClass.getName()是类的完全限定名
//保存小写名称的映射关系
char c = beanClass.getSimpleName().toCharArray()[0];
result.add(doCreateBeanDefinition(Character.isLowerCase(c)
? beanClass.getSimpleName()
: toLowerFirstCase(beanClass.getSimpleName()),
beanClass.getName()));
//保存完全限定名的映射关系
result.add(doCreateBeanDefinition(beanClass.getName(), beanClass.getName()));
//获取该实现类的接口列表
Class<?>[] interfaces = beanClass.getInterfaces();
for (Class<?> i : interfaces) {
//如果是多个实现类,只能覆盖
//为什么?因为Spring没那么智能,就是这么傻
//这个时候,可以自定义名字
//保存接口的完全限定名的映射关系
result.add(doCreateBeanDefinition(i.getName(), beanClass.getName()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* @Description: 将配置信息解析为definition规范
* @Author: PABLO
* @Date: 2022/5/7 12:31
* @Params: [factoryBeanName, beanClassName 是完全限定名]
* @Return: GPBeanDefinition
**/
private PABLO_BeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName) {
PABLO_BeanDefinition beanDefinition = new PABLO_BeanDefinition();
beanDefinition.setBeanClassName(beanClassName);
beanDefinition.setFactoryBeanName(factoryBeanName);
System.out.println(beanDefinition);
return beanDefinition;
}
/**
* @Description:大写转小写
* @Author: PABLO
* @Date: 2022/5/7 12:34
* @Params: [simpleName]
* @Return: java.lang.String
**/
private String toLowerFirstCase(String simpleName) {
char[] chars = simpleName.toCharArray();
//大小写字母的ASCII码相差32,
//而且大写字母的ASCII码要小于小写字母的ASCII码
//在Java中,对char做算学运算,实际上就是对ASCII码做算学运算
chars[0] += 32;
return String.valueOf(chars);
}
}
package com.gator.spring.framework.beans.support;
import com.gator.spring.framework.beans.PABLO_BeanFactory;
import com.gator.spring.framework.beans.factory.config.PABLO_BeanDefinition;
import com.gator.spring.framework.context.support.PABLO_AbstractApplicationContext;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author PABLO
* @Date 2022/5/7 11:36
* @Desc IOC容器的默认实现 兜底
*/
public class PABLO_DefaultListableBeanFactory
extends PABLO_AbstractApplicationContext
implements PABLO_BeanFactory{
//存储对象描述信息map集合
//key为对象在BeanFactory中的名称,默认小写字母开头
public final Map<String, PABLO_BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, PABLO_BeanDefinition>(256);
@Override
public Object getBean(String beanName) throws Exception {
return null;
}
}
package com.gator.spring.framework.beans;
/**
* @Author PABLO
* @Date 2022/5/7 12:47
* @Desc 对象包装类 创建对象成功后返回的装饰器
*/
public class PABLO_BeanWrapper {
//被包装的bean实例
private Object wrappedInstance;
private Class<?> wrappedClass;
public PABLO_BeanWrapper(Object wrappedInstance){
this.wrappedInstance = wrappedInstance;
}
public Object getWrappedInstance(){
return this.wrappedInstance;
}
// 返回代理以后的Class
// 可能会是这个 $Proxy0
public Class<?> getWrappedClass(){
return this.wrappedInstance.getClass();
}
}
/**
* @Authror PABLO
* @Date 2022/5/7 11:21
* @Desc
*/
public interface PABLO_FactoryBean {
}
package com.gator.spring.framework.context;
import org.springframework.beans.BeansException;
/**
* @Authror PABLO
* @Date 2022/5/7 11:58
* @Desc 解耦获得IOC容器的顶层设计
* 通过监听器(Observer)扫描所有类,只要实现此接口,将调用setApplicationContext(),将IOC容器注入到目标类中
*/
public interface PABLO_ApplicationContextAware {
void setApplicationContext(PABLO_ApplicationContext applicationContext) throws BeansException;
}
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.giant-gator.spring</groupId>
<artifactId>gator-spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gator.spring</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
<build>
<finalName>${artifactId}</finalName>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
<exclude>**/*.class</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<encoding>UTF-8</encoding>
<outputDirectory>${basedir}/target/classes</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.26</version>
<configuration>
<webDefaultXml>src/main/resources/webdefault.xml</webDefaultXml>
<contextPath>/</contextPath>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>80</port>
</connector>
</connectors>
<scanIntervalSeconds>0</scanIntervalSeconds>
<scanTargetPatterns>
<scanTargetPattern>
<directory>src/main/webapp</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</scanTargetPattern>
</scanTargetPatterns>
<systemProperties>
<systemProperty>
<name>
javax.xml.parsers.DocumentBuilderFactory
</name>
<value>
com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
</value>
</systemProperty>
<systemProperty>
<name>
javax.xml.parsers.SAXParserFactory
</name>
<value>
com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
</value>
</systemProperty>
<systemProperty>
<name>
javax.xml.transform.TransformerFactory
</name>
<value>
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
</value>
</systemProperty>
<systemProperty>
<name>org.eclipse.jetty.util.URI.charset</name>
<value>UTF-8</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
<webResources>
<resource>
<!-- this is relative to the pom.xml directory -->
<directory>src/main/resources/</directory>
<targetPath>WEB-INF/classes</targetPath>
<includes>
<include>**/*.*</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<!-- this is relative to the pom.xml directory -->
<directory>src/main/resources</directory>
<targetPath>WEB-INF/classes</targetPath>
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.zeroturnaround</groupId>
<artifactId>javarebel-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-rebel-xml</id>
<phase>process-resources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<version>1.0.5</version>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.zeroturnaround
</groupId>
<artifactId>
javarebel-maven-plugin
</artifactId>
<versionRange>
[1.0.5,)
</versionRange>
<goals>
<goal>generate</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
谢谢大家支持,如对你有帮助,可以奉献一下你的爱心