Spring框架 作为一个轻量级的开源框架不仅给我们的开发工作带来了许多便利,同时也为众多开源框架的研究提供了不可或缺的指导思想。Spring最为核心的两大功能特性就是IOC和AOP.下面主要介绍SpringIOC及自己实现SpringIOC
1.SpringIOC
SpringIOC 指的是控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。
IOC容器 负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。交由Spring来管理这些,实现解耦!
2.手写SpringIOC大致思路
1、建立自己的创建Bean的注解和输出Bean的注解。分别用于Bean头部初始化Bean、字段标识获取Bean。建立自己的初始化接口。用于实现Bean被加载完后执行init方法。
2、用包扫描器扫描监管范围内所有的class、并通过反射扫描所有类是否包含创建Bean的注解进行初始化操作并存储至Bean容器
3、从Bean容器获得所有Bean、并通过反射扫描所有Bean的所有字段是否包含的输出Bean的注解进行赋值操作
4、从Bean容器获得所有Bean、判断是否实现初始化接口并执行init方法。
3.手写SpringIOC步骤
3.1.自定注解
自定义Service注解
package org.springframework.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.annotation
* @CreateTime: 2020-10-01 13:38
* @Description: 自定义Service注解
*/
//这个注解可以作用在运行期
(RetentionPolicy.RUNTIME)
//指定该注解可以作用在类上
(ElementType.TYPE)
public @interface Service {
String value() default "";
}
自定义Controller注解
package org.springframework.annotation;
import java.lang.annotation.*;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.annotation
* @CreateTime: 2020-10-01 13:40
* @Description: 自定义Controller注解
*/
//这个注解可以作用在运行期
(RetentionPolicy.RUNTIME)
//指定该注解可以作用在类上
(ElementType.TYPE)
public @interface Controller {
String value() default "";
}
自定义Autowired注解
package org.springframework.annotation;
import java.lang.annotation.*;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.annotation
* @CreateTime: 2020-10-01 13:42
* @Description: 自定义Autowired注解
*/
//这个注解可以作用在运行期
(RetentionPolicy.RUNTIME)
//指定该注解可以作用在类上
(ElementType.FIELD)
public @interface Autowired {
}
3.2.编写业务代码
创建UserService业务逻辑层接口
package com.itxiongmao.service;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: com.itxiongmao.service
* @CreateTime: 2020-10-01 13:50
* @Description: TODO
*/
public interface UserService {
void serviceMethod();
}
创建UserService业务逻辑层接口实现类
package com.itxiongmao.service.impl;
import com.itxiongmao.service.UserService;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: com.itxiongmao.service.impl
* @CreateTime: 2020-10-01 13:51
* @Description: TODO
*/
public class UserServiceImpl implements UserService {
public void serviceMethod() {
System.out.println("业务逻辑层方法");
}
}
创建UserCOntroller控制层
package com.itxiongmao.controller;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: com.itxiongmao.controller
* @CreateTime: 2020-10-01 13:53
* @Description: TODO
*/
public class UserController {
}
使用注解进行关系注入,控制层注入业务逻辑层
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: com.itxiongmao.service.impl
* @CreateTime: 2020-10-01 13:51
* @Description: TODO
*/
public class UserServiceImpl implements UserService {
public void serviceMethod() {
System.out.println("业务逻辑层方法");
}
}
package com.itxiongmao.controller;
import com.itxiongmao.service.UserService;
import org.springframework.annotation.Autowired;
import org.springframework.annotation.Controller;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: com.itxiongmao.controller
* @CreateTime: 2020-10-01 13:53
* @Description: TODO
*/
public class UserController {
UserService userService;
public void controllerMethod(){
userService.serviceMethod();
}
}
3.3.类加载器获得资源
3.3.1.创建IOC容器类
package org.springframework.ioc;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.ioc
* @CreateTime: 2020-10-01 14:00
* @Description: TODO
*/
public class Container {
/**
* @param path 要扫描的包路径
*/
public Container(String path){
}
}
3.3.2.准备要扫描的类配置文件
ioc.properties
componentScan=com.itxiongmao=com.itxiongmao
3.3.3.获取要扫描的包
package org.springframework.ioc;
import java.io.IOException;
import java.util.Properties;
import java.io.InputStream;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.ioc
* @CreateTime: 2020-10-01 14:00
* @Description: TODO
*/
public class Container {
public static final String COMPONENTSCAN="componentScan";
/**
* @param path 要扫描的包路径
*/
public Container(String path){
String packagePath = this.loadResource(path);
System.out.println(packagePath);
}
/**
* 01-定位要扫描的包
*/
public String loadResource(String path){
//hashTable的子类
Properties properties = new Properties();
//定位
ClassLoader classLoader = getClassLoader();
//把ioc.properties转换为io输入流
InputStream resourceAsStream = classLoader.getResourceAsStream(path);
try {
properties.load(resourceAsStream);
String property = properties.getProperty(COMPONENTSCAN);
return property;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public ClassLoader getClassLoader(){
//当前线程的累加载器
return Thread.currentThread().getContextClassLoader();
}
}
3.3.4.获得要扫描类全路径
package org.springframework.ioc;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import java.io.InputStream;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.ioc
* @CreateTime: 2020-10-01 14:00
* @Description: TODO
*/
public class Container {
public static final String COMPONENTSCAN="componentScan";
/**
* @param path 要扫描的包路径
*/
public Container(String path){
String packagePath = this.loadResource(path);
System.out.println(packagePath);
this.loadAllClass(packagePath);
}
private void loadAllClass(String packagePath) {
ClassLoader classLoader = this.getClassLoader();
URL resource = classLoader.getResource("");
String replace = packagePath.replace(".", File.separator);
File file = new File(resource.toString().replace("file:/","") + replace);
System.out.println(file);
}
}
3.3.5.获得要扫描类
package org.springframework.ioc;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import java.io.InputStream;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.ioc
* @CreateTime: 2020-10-01 14:00
* @Description: TODO
*/
public class Container {
public static final String COMPONENTSCAN="componentScan";
//类的全路径 线程安全的hashSet com.itxiongmao.controller.UserController
private Set<String> stringSet = new CopyOnWriteArraySet<String>();
/**
* @param path 要扫描的包路径
*/
public Container(String path){
String packagePath = this.loadResource(path);
System.out.println(packagePath);
this.loadAllClass(packagePath);
System.out.println("IOC容器类集合:"+stringSet);
}
/**
* 01-定位要扫描的包
*/
public String loadResource(String path){
//hashTable的子类
Properties properties = new Properties();
//定位
ClassLoader classLoader = getClassLoader();
//把ioc.properties转换为io输入流
InputStream resourceAsStream = classLoader.getResourceAsStream(path);
try {
properties.load(resourceAsStream);
String property = properties.getProperty(COMPONENTSCAN);
return property;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public ClassLoader getClassLoader(){
//当前线程的累加载器
return Thread.currentThread().getContextClassLoader();
}
private void loadAllClass(String packagePath) {
ClassLoader classLoader = this.getClassLoader();
URL resource = classLoader.getResource("");
String replace = packagePath.replace(".", File.separator);
File file = new File(resource.toString().replace("file:/","") + replace);
//获得所有的class结尾的文件
System.out.println(file);
diGui(file,packagePath);
return;
}
public void diGui(File file,String packagePath){
if(file==null)return;
if(file.isDirectory()){
//获得当前包下面所有文件 controller service
File[] files = file.listFiles();
if(files!=null)
for(File f:files){
if(f.isDirectory()){
diGui(f,packagePath+"."+f.getName());
}else {
//UserController.class
String name = f.getName();
if(name.endsWith(".class")) {
String substring = name.substring(0, name.indexOf("."));
stringSet.add(packagePath+"."+substring);
}
}
}
}else{
//UserController.class
String name = file.getName();
if(name.endsWith(".class")) {
//UserController cn.cdqf.controller.UserController
String substring = name.substring(0, name.indexOf("."));
stringSet.add(packagePath+"."+substring);
}
}
}
}
3.4.初始化IOC容器
package org.springframework.ioc;
import org.springframework.annotation.Controller;
import org.springframework.annotation.Service;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.*;
import java.io.InputStream;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.ioc
* @CreateTime: 2020-10-01 14:00
* @Description: TODO
*/
public class Container {
public static final String COMPONENTSCAN="componentScan";
//类的全路径 线程安全的hashSet com.itxiongmao.controller.UserController
private Set<String> stringSet = new CopyOnWriteArraySet<String>();
//定义一个map<Class<?>,List<Object>> key:接口类 List<Object>:实现类对象
//key:UserService value 所有实现了该接口得子类对象
private Map<Class<?>,List<Object>> superIocMap = new ConcurrentHashMap<Class<?>,List<Object>>();
//根据指定的bean名字来存储
//key:userServiceImpl(默认首字母小写) value:new UserServiceImpl
private Map<String,Object> nameIocMap = new ConcurrentHashMap<String,Object>();
//定义ioc容器 iocMap key:UserServiceImpl.class 就是被添加了service,controller等注解得类class对象
//value :就是对应对象 new UserServiceImpl
private Map<Class<?>,Object> iocMap = new ConcurrentHashMap<Class<?>,Object>();
/**
* @param path 要扫描的包路径
*/
public Container(String path){
String packagePath = this.loadResource(path);
System.out.println(packagePath);
this.loadAllClass(packagePath);
System.out.println("IOC容器类集合:"+stringSet);
System.out.println("superIocMap="+superIocMap);
System.out.println("nameIocMap="+nameIocMap);
System.out.println("iocMap="+iocMap);
}
/**
* 01-定位要扫描的包
*/
public String loadResource(String path){
//hashTable的子类
Properties properties = new Properties();
//定位
ClassLoader classLoader = getClassLoader();
//把ioc.properties转换为io输入流
InputStream resourceAsStream = classLoader.getResourceAsStream(path);
try {
properties.load(resourceAsStream);
String property = properties.getProperty(COMPONENTSCAN);
return property;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public ClassLoader getClassLoader(){
//当前线程的累加载器
return Thread.currentThread().getContextClassLoader();
}
private void loadAllClass(String packagePath) {
ClassLoader classLoader = this.getClassLoader();
URL resource = classLoader.getResource("");
String replace = packagePath.replace(".", File.separator);
File file = new File(resource.toString().replace("file:/","") + replace);
//获得所有的class结尾的文件
System.out.println(file);
diGui(file,packagePath);
//初始化IOC容器
this.doInit();
return;
}
public void diGui(File file,String packagePath){
if(file==null)return;
if(file.isDirectory()){
//获得当前包下面所有文件 controller service
File[] files = file.listFiles();
if(files!=null)
for(File f:files){
if(f.isDirectory()){
diGui(f,packagePath+"."+f.getName());
}else {
//UserController.class
String name = f.getName();
if(name.endsWith(".class")) {
String substring = name.substring(0, name.indexOf("."));
stringSet.add(packagePath+"."+substring);
}
}
}
}else{
//UserController.class
String name = file.getName();
if(name.endsWith(".class")) {
//UserController cn.cdqf.controller.UserController
String substring = name.substring(0, name.indexOf("."));
stringSet.add(packagePath+"."+substring);
}
}
}
List<Class<? extends Annotation>> list = Arrays.asList(Controller.class, Service.class);
private void doInit() {
try {
if (stringSet != null)
for (String path : stringSet) {
Class<?> aClass = Class.forName(path);
//判断这些class里面是否存在我们标记的注解
for (Class<? extends Annotation> aClass1 : list) {
//aClass对面上面是否有aClass1这个注解
if(aClass.isAnnotationPresent(aClass1)){
//要交给spring管理
//创建对象 调用无参构造创建对象
//obj :UserController对象 以及UserServiceImpl对象
Object obj = aClass.newInstance();
//把有controller或者service注解的类 加入了ioc容器
//存入ioc
iocMap.put(aClass,obj);
Class<?>[] interfaces = aClass.getInterfaces();
if(interfaces!=null){
//一个接口有多个实现类 有可能当前接口已经都放入了实现类
for (Class<?> anInterface : interfaces) {
List<Object> objects = superIocMap.get(anInterface);
if(objects==null){//当前接口对应的对象还没有放过
ArrayList<Object> objects1 = new ArrayList<Object>();
objects1.add(obj);
superIocMap.put(anInterface,objects1);
}else{//当前接口对应的对象放过
objects.add(obj);
}
}
}
//获取名字
if(aClass1==Service.class){
Service annotation = aClass.getAnnotation(Service.class);
String value = annotation.value();
if(value.equals("")){
//首字母小写
String simpleName = aClass.getSimpleName();
String name = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
value = name;
}
if(nameIocMap.containsKey(value)){
throw new RuntimeException("non-compatible bean definition of same name");
}
nameIocMap.put(value,obj);
}
if(aClass1== Controller.class){
Controller annotation = aClass.getAnnotation(Controller.class);
String value = annotation.value();
if(value.equals("")){
//首字母小写
String simpleName = aClass.getSimpleName();
String name = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
value = name;
}
if(nameIocMap.containsKey(value)){
throw new RuntimeException("相同的bean名字non-compatible bean definition of same name");
}
nameIocMap.put(value,obj);
}
break;
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
3.5.依赖注入
package org.springframework.ioc;
import org.springframework.annotation.Autowired;
import org.springframework.annotation.Controller;
import org.springframework.annotation.Service;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.io.InputStream;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: org.springframework.ioc
* @CreateTime: 2020-10-01 14:00
* @Description: TODO
*/
public class Container {
public static final String COMPONENTSCAN="componentScan";
//类的全路径 线程安全的hashSet com.itxiongmao.controller.UserController
private Set<String> stringSet = new CopyOnWriteArraySet<String>();
//定义一个map<Class<?>,List<Object>> key:接口类 List<Object>:实现类对象
//key:UserService value 所有实现了该接口得子类对象
private Map<Class<?>,List<Object>> superIocMap = new ConcurrentHashMap<Class<?>,List<Object>>();
//根据指定的bean名字来存储
//key:userServiceImpl(默认首字母小写) value:new UserServiceImpl
private Map<String,Object> nameIocMap = new ConcurrentHashMap<String,Object>();
//定义ioc容器 iocMap key:UserServiceImpl.class 就是被添加了service,controller等注解得类class对象
//value :就是对应对象 new UserServiceImpl
private Map<Class<?>,Object> iocMap = new ConcurrentHashMap<Class<?>,Object>();
/**
* @param path 要扫描的包路径
*/
public Container(String path){
String packagePath = this.loadResource(path);
System.out.println(packagePath);
this.loadAllClass(packagePath);
System.out.println("IOC容器类集合:"+stringSet);
System.out.println("superIocMap="+superIocMap);
System.out.println("nameIocMap="+nameIocMap);
System.out.println("iocMap="+iocMap);
}
/**
* 01-定位要扫描的包
*/
public String loadResource(String path){
//hashTable的子类
Properties properties = new Properties();
//定位
ClassLoader classLoader = getClassLoader();
//把ioc.properties转换为io输入流
InputStream resourceAsStream = classLoader.getResourceAsStream(path);
try {
properties.load(resourceAsStream);
String property = properties.getProperty(COMPONENTSCAN);
return property;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public ClassLoader getClassLoader(){
//当前线程的累加载器
return Thread.currentThread().getContextClassLoader();
}
private void loadAllClass(String packagePath) {
ClassLoader classLoader = this.getClassLoader();
URL resource = classLoader.getResource("");
String replace = packagePath.replace(".", File.separator);
File file = new File(resource.toString().replace("file:/","") + replace);
//获得所有的class结尾的文件
System.out.println(file);
diGui(file,packagePath);
//初始化IOC容器
this.doInit();
//执行依赖注入
this.doPopulation();
return;
}
public void diGui(File file,String packagePath){
if(file==null)return;
if(file.isDirectory()){
//获得当前包下面所有文件 controller service
File[] files = file.listFiles();
if(files!=null)
for(File f:files){
if(f.isDirectory()){
diGui(f,packagePath+"."+f.getName());
}else {
//UserController.class
String name = f.getName();
if(name.endsWith(".class")) {
String substring = name.substring(0, name.indexOf("."));
stringSet.add(packagePath+"."+substring);
}
}
}
}else{
//UserController.class
String name = file.getName();
if(name.endsWith(".class")) {
//UserController cn.cdqf.controller.UserController
String substring = name.substring(0, name.indexOf("."));
stringSet.add(packagePath+"."+substring);
}
}
}
List<Class<? extends Annotation>> list = Arrays.asList(Controller.class, Service.class);
private void doInit() {
try {
if (stringSet != null)
for (String path : stringSet) {
Class<?> aClass = Class.forName(path);
//判断这些class里面是否存在我们标记的注解
for (Class<? extends Annotation> aClass1 : list) {
//aClass对面上面是否有aClass1这个注解
if(aClass.isAnnotationPresent(aClass1)){
//要交给spring管理
//创建对象 调用无参构造创建对象
//obj :UserController对象 以及UserServiceImpl对象
Object obj = aClass.newInstance();
//把有controller或者service注解的类 加入了ioc容器
//存入ioc
iocMap.put(aClass,obj);
Class<?>[] interfaces = aClass.getInterfaces();
if(interfaces!=null){
//一个接口有多个实现类 有可能当前接口已经都放入了实现类
for (Class<?> anInterface : interfaces) {
List<Object> objects = superIocMap.get(anInterface);
if(objects==null){//当前接口对应的对象还没有放过
ArrayList<Object> objects1 = new ArrayList<Object>();
objects1.add(obj);
superIocMap.put(anInterface,objects1);
}else{//当前接口对应的对象放过
objects.add(obj);
}
}
}
//获取名字
if(aClass1==Service.class){
Service annotation = aClass.getAnnotation(Service.class);
String value = annotation.value();
if(value.equals("")){
//首字母小写
String simpleName = aClass.getSimpleName();
String name = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
value = name;
}
if(nameIocMap.containsKey(value)){
throw new RuntimeException("non-compatible bean definition of same name");
}
nameIocMap.put(value,obj);
}
if(aClass1== Controller.class){
Controller annotation = aClass.getAnnotation(Controller.class);
String value = annotation.value();
if(value.equals("")){
//首字母小写
String simpleName = aClass.getSimpleName();
String name = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
value = name;
}
if(nameIocMap.containsKey(value)){
throw new RuntimeException("相同的bean名字non-compatible bean definition of same name");
}
nameIocMap.put(value,obj);
}
break;
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 对ioc map进行依赖注入
*/
private void doPopulation() {
//所有交给spring管理的类的Class对象
Set<Class<?>> classes = iocMap.keySet();
if(classes==null)return;
for (Class<?> aClass : classes) {
populationOne(aClass);
}
}
private void populationOne(Class<?> aClass) {
//获得当前class里面所有属性 ,然后判断这些属性上面是否有autowired
Field[] declaredFields = aClass.getDeclaredFields();
if(declaredFields==null) return;
for (Field declaredField : declaredFields) {
//判断属性上是否有Autowired注解
boolean annotationPresent = declaredField.isAnnotationPresent(Autowired.class);
//就需要依赖注入
if(annotationPresent){
//根据类型注入最优先
Object bean = this.getBean(declaredField.getType());
if(bean==null){
//名字其次
String name = declaredField.getName();
bean = this.getBean(name);
if(bean==null){//有可能是接口
bean = this.getBeanByInterface(declaredField.getType());
if(bean==null){
//没有对象能依赖注入
throw new RuntimeException("expected at least 1 bean which qualifies as autowire candidate");
}
}
}
//bean已经在ioc容器中取到了 赋值
declaredField.setAccessible(true);
try {
//对属性赋值
declaredField.set(iocMap.get(aClass),bean);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
//1.按照接口类型来取子类对象
public Object getBeanByInterface(Class<?> clazz){
List<Object> objects = superIocMap.get(clazz);
if(objects==null)return null;
if(objects.size()>1){
throw new RuntimeException(clazz.getName()+" not available: expected single matching bean but found "+objects.size());
}
return objects.get(0);
}
//2.按照本类型来取对象
public Object getBean(Class<?> clazz){
return iocMap.get(clazz);
}
//3.按照名字来取对象
public Object getBean(String beanName){
return nameIocMap.get(beanName);
}
}
4.测试
package com.itxiongmao.test;
import com.itxiongmao.controller.UserController;
import com.itxiongmao.service.UserService;
import com.itxiongmao.service.impl.UserServiceImpl;
import org.springframework.ioc.Container;
/**
* @BelongsProject: SpringIOC
* @BelongsPackage: test
* @CreateTime: 2020-10-01 14:08
* @Description: TODO
*/
public class TestSpringIoc {
public static void main(String[] args) {
Container container=new Container("ioc.properties");
System.out.println(container);
UserController userController = (UserController)container.getBean(UserController.class);
userController.controllerMethod();
UserService userService = (UserService) container.getBean(UserServiceImpl.class);
userService.serviceMethod();
UserService userService1 = (UserService) container.getBeanByInterface(UserService.class);
userService1.serviceMethod();
}
}