自做网站视频,成都住建局官网网签,百度云网站建设教程视频,外贸网站建设怎么建设学习的最大理由是想摆脱平庸#xff0c;早一天就多一份人生的精彩#xff1b;迟一天就多一天平庸的困扰。各位小伙伴#xff0c;如果您#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持#xff0c;想组团高效学习… 想写博客但无从下手#xff0c;急需… 学习的最大理由是想摆脱平庸早一天就多一份人生的精彩迟一天就多一天平庸的困扰。各位小伙伴如果您 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持想组团高效学习… 想写博客但无从下手急需写作干货注入能量… 热爱写作愿意让自己成为更好的人… 文章目录 前言一、回顾Java反射二、实现Spring的IoC①搭建子模块②准备测试需要的bean③定义注解④定义bean容器接口⑤编写注解bean容器接口实现⑥编写扫描bean逻辑⑦java类标识Bean注解⑧测试Bean加载⑨依赖注入⑩依赖注入实现 总结 前言
我们都知道Spring框架的IOC是基于Java反射机制实现的下面我们先回顾一下java反射。 一、回顾Java反射
Java反射机制是在运行状态中对于任意一个类都能够知道这个类的所有属性和方法对于任意一个对象都能够调用它的任意方法和属性这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说反射机制指的是程序在运行时能够获取自身的信息。
要想解剖一个类必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API**1java.lang.Class2java.lang.reflect**所以Class对象是反射的根源。
自定义类
package com.atguigu.reflect;public class Car {//属性private String name;private int age;private String color;//无参数构造public Car() {}//有参数构造public Car(String name, int age, String color) {this.name name;this.age age;this.color color;}//普通方法private void run() {System.out.println(私有方法-run.....);}//get和set方法public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}public String getColor() {return color;}public void setColor(String color) {this.color color;}Overridepublic String toString() {return Car{ name name \ , age age , color color \ };}
}编写测试类
package com.atguigu.reflect;import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class TestCar {//1、获取Class对象多种方式Testpublic void test01() throws Exception {//1 类名.classClass clazz1 Car.class;//2 对象.getClass()Class clazz2 new Car().getClass();//3 Class.forName(全路径)Class clazz3 Class.forName(com.atguigu.reflect.Car);//实例化Car car (Car)clazz3.getConstructor().newInstance();System.out.println(car);}//2、获取构造方法Testpublic void test02() throws Exception {Class clazz Car.class;//获取所有构造// getConstructors()获取所有public的构造方法
// Constructor[] constructors clazz.getConstructors();// getDeclaredConstructors()获取所有的构造方法public privateConstructor[] constructors clazz.getDeclaredConstructors();for (Constructor c:constructors) {System.out.println(方法名称c.getName() 参数个数c.getParameterCount());}//指定有参数构造创建对象//1 构造public
// Constructor c1 clazz.getConstructor(String.class, int.class, String.class);
// Car car1 (Car)c1.newInstance(夏利, 10, 红色);
// System.out.println(car1);//2 构造privateConstructor c2 clazz.getDeclaredConstructor(String.class, int.class, String.class);c2.setAccessible(true);Car car2 (Car)c2.newInstance(捷达, 15, 白色);System.out.println(car2);}//3、获取属性Testpublic void test03() throws Exception {Class clazz Car.class;Car car (Car)clazz.getDeclaredConstructor().newInstance();//获取所有public属性//Field[] fields clazz.getFields();//获取所有属性包含私有属性Field[] fields clazz.getDeclaredFields();for (Field field:fields) {if(field.getName().equals(name)) {//设置允许访问field.setAccessible(true);field.set(car,五菱宏光);System.out.println(car);}System.out.println(field.getName());}}//4、获取方法Testpublic void test04() throws Exception {Car car new Car(奔驰,10,黑色);Class clazz car.getClass();//1 public方法Method[] methods clazz.getMethods();for (Method m1:methods) {//System.out.println(m1.getName());//执行方法 toStringif(m1.getName().equals(toString)) {String invoke (String)m1.invoke(car);//System.out.println(toString执行了invoke);}}//2 private方法Method[] methodsAll clazz.getDeclaredMethods();for (Method m:methodsAll) {//执行方法 runif(m.getName().equals(run)) {m.setAccessible(true);m.invoke(car);}}}
}二、实现Spring的IoC
我们知道IoC控制反转和DI依赖注入是Spring里面核心的东西那么我们如何自己手写出这样的代码呢下面我们就一步一步写出Spring框架最核心的部分。
①搭建子模块
搭建模块guigu-spring搭建方式如其他spring子模块
②准备测试需要的bean
添加依赖
dependencies!--junit5测试--dependencygroupIdorg.junit.jupiter/groupIdartifactIdjunit-jupiter-api/artifactIdversion5.3.1/version/dependency
/dependencies创建UserDao接口
package com.atguigu.spring6.test.dao;public interface UserDao {public void print();
}创建UserDaoImpl实现
package com.atguigu.spring6.test.dao.impl;import com.atguigu.spring.dao.UserDao;public class UserDaoImpl implements UserDao {Overridepublic void print() {System.out.println(Dao层执行结束);}
}
创建UserService接口
package com.atguigu.spring6.test.service;public interface UserService {public void out();
}创建UserServiceImpl实现类
package com.atguigu.spring.test.service.impl;import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.service.UserService;Bean
public class UserServiceImpl implements UserService {// private UserDao userDao;Overridepublic void out() {//userDao.print();System.out.println(Service层执行结束);}
}
③定义注解
我们通过注解的形式加载bean与实现依赖注入
bean注解
package com.atguigu.spring.core.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
public interface Bean {
}依赖注入注解
package com.atguigu.spring.core.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Target({ElementType.FIELD})
Retention(RetentionPolicy.RUNTIME)
public interface Di {
}说明上面两个注解可以随意取名
④定义bean容器接口
package com.atguigu.spring.core;public interface ApplicationContext {Object getBean(Class clazz);
}⑤编写注解bean容器接口实现
AnnotationApplicationContext基于注解扫描bean
package com.atguigu.spring.core;import java.util.HashMap;public class AnnotationApplicationContext implements ApplicationContext {//存储bean的容器private HashMapClass, Object beanFactory new HashMap();Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}/*** 根据包扫描加载bean* param basePackage*/public AnnotationApplicationContext(String basePackage) {}
}⑥编写扫描bean逻辑
我们通过构造方法传入包的base路径扫描被Bean注解的java对象完整代码如下
package com.atguigu.spring.core;import com.atguigu.spring.core.annotation.Bean;import java.io.File;
import java.util.HashMap;public class AnnotationApplicationContext implements ApplicationContext {//存储bean的容器private HashMapClass, Object beanFactory new HashMap();private static String rootPath;Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}/*** 根据包扫描加载bean* param basePackage*/public AnnotationApplicationContext(String basePackage) {try {String packageDirName basePackage.replaceAll(\\., \\\\);EnumerationURL dirs Thread.currentThread().getContextClassLoader().getResources(packageDirName);while (dirs.hasMoreElements()) {URL url dirs.nextElement();String filePath URLDecoder.decode(url.getFile(),utf-8);rootPath filePath.substring(0, filePath.length()-packageDirName.length());loadBean(new File(filePath));}} catch (Exception e) {throw new RuntimeException(e);}}private void loadBean(File fileParent) {if (fileParent.isDirectory()) {File[] childrenFiles fileParent.listFiles();if(childrenFiles null || childrenFiles.length 0){return;}for (File child : childrenFiles) {if (child.isDirectory()) {//如果是个文件夹就继续调用该方法,使用了递归loadBean(child);} else {//通过文件路径转变成全类名,第一步把绝对路径部分去掉String pathWithClass child.getAbsolutePath().substring(rootPath.length() - 1);//选中class文件if (pathWithClass.contains(.class)) {// com.xinzhi.dao.UserDao//去掉.class后缀并且把 \ 替换成 .String fullName pathWithClass.replaceAll(\\\\, .).replace(.class, );try {Class? aClass Class.forName(fullName);//把非接口的类实例化放在map中if(!aClass.isInterface()){Bean annotation aClass.getAnnotation(Bean.class);if(annotation ! null){Object instance aClass.newInstance();//判断一下有没有接口if(aClass.getInterfaces().length 0) {//如果有接口把接口的class当成key实例对象当成valueSystem.out.println(正在加载【 aClass.getInterfaces()[0] 】,实例对象是 instance.getClass().getName());beanFactory.put(aClass.getInterfaces()[0], instance);}else{//如果有接口把自己的class当成key实例对象当成valueSystem.out.println(正在加载【 aClass.getName() 】,实例对象是 instance.getClass().getName());beanFactory.put(aClass, instance);}}}} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {e.printStackTrace();}}}}}}}⑦java类标识Bean注解
Bean
public class UserServiceImpl implements UserServiceBean
public class UserDaoImpl implements UserDao ⑧测试Bean加载
package com.atguigu.spring;import com.atguigu.spring.core.AnnotationApplicationContext;
import com.atguigu.spring.core.ApplicationContext;
import com.atguigu.spring.test.service.UserService;
import org.junit.jupiter.api.Test;public class SpringIocTest {Testpublic void testIoc() {ApplicationContext applicationContext new AnnotationApplicationContext(com.atguigu.spring.test);UserService userService (UserService)applicationContext.getBean(UserService.class);userService.out();System.out.println(run success);}
}控制台打印测试
⑨依赖注入
只要userDao.print();调用成功说明就注入成功
package com.atguigu.spring.test.service.impl;import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.core.annotation.Di;
import com.atguigu.spring.dao.UserDao;
import com.atguigu.spring.service.UserService;Bean
public class UserServiceImpl implements UserService {Diprivate UserDao userDao;Overridepublic void out() {userDao.print();System.out.println(Service层执行结束);}
}执行第八步报错了说明当前userDao是个空对象
⑩依赖注入实现
package com.atguigu.spring.core;import com.atguigu.spring.core.annotation.Bean;
import com.atguigu.spring.core.annotation.Di;import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;public class AnnotationApplicationContext implements ApplicationContext {//存储bean的容器private HashMapClass, Object beanFactory new HashMap();private static String rootPath;Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}/*** 根据包扫描加载bean* param basePackage*/public AnnotationApplicationContext(String basePackage) {try {String packageDirName basePackage.replaceAll(\\., \\\\);EnumerationURL dirs Thread.currentThread().getContextClassLoader().getResources(packageDirName);while (dirs.hasMoreElements()) {URL url dirs.nextElement();String filePath URLDecoder.decode(url.getFile(),utf-8);rootPath filePath.substring(0, filePath.length()-packageDirName.length());loadBean(new File(filePath));}} catch (Exception e) {throw new RuntimeException(e);}//依赖注入loadDi();}private void loadBean(File fileParent) {if (fileParent.isDirectory()) {File[] childrenFiles fileParent.listFiles();if(childrenFiles null || childrenFiles.length 0){return;}for (File child : childrenFiles) {if (child.isDirectory()) {//如果是个文件夹就继续调用该方法,使用了递归loadBean(child);} else {//通过文件路径转变成全类名,第一步把绝对路径部分去掉String pathWithClass child.getAbsolutePath().substring(rootPath.length() - 1);//选中class文件if (pathWithClass.contains(.class)) {// com.xinzhi.dao.UserDao//去掉.class后缀并且把 \ 替换成 .String fullName pathWithClass.replaceAll(\\\\, .).replace(.class, );try {Class? aClass Class.forName(fullName);//把非接口的类实例化放在map中if(!aClass.isInterface()){Bean annotation aClass.getAnnotation(Bean.class);if(annotation ! null){Object instance aClass.newInstance();//判断一下有没有接口if(aClass.getInterfaces().length 0) {//如果有接口把接口的class当成key实例对象当成valueSystem.out.println(正在加载【 aClass.getInterfaces()[0] 】,实例对象是 instance.getClass().getName());beanFactory.put(aClass.getInterfaces()[0], instance);}else{//如果有接口把自己的class当成key实例对象当成valueSystem.out.println(正在加载【 aClass.getName() 】,实例对象是 instance.getClass().getName());beanFactory.put(aClass, instance);}}}} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {e.printStackTrace();}}}}}}private void loadDi() {for(Map.EntryClass,Object entry : beanFactory.entrySet()){//就是咱们放在容器的对象Object obj entry.getValue();Class? aClass obj.getClass();Field[] declaredFields aClass.getDeclaredFields();for (Field field : declaredFields){Di annotation field.getAnnotation(Di.class);if( annotation ! null ){field.setAccessible(true);try {System.out.println(正在给【obj.getClass().getName()】属性【 field.getName() 】注入值【 beanFactory.get(field.getType()).getClass().getName() 】);field.set(obj,beanFactory.get(field.getType()));} catch (IllegalAccessException e) {e.printStackTrace();}}}}}}执行第八步执行成功依赖注入成功 总结
以上就是Spring之容器IOC3的相关知识点希望对你有所帮助。 积跬步以至千里积怠惰以至深渊。时代在这跟着你一起努力哦