spring设计架构
"
Test:测试模块
Core container :核心模块
Beans :将对象设置成Beans,Core核心工具类,Context上下文将Beans和Core组装运行环境,SpEL表达式语言
Aop :将java中动态代理为基础一系列横线切面
Data:操作数据库
Web:web组件开发支持
Jsp实现原理
日志
Url
反射
三种获取Class方法
https://www.cnblogs.com/wwjj4811/p/12539804.html
注解
自研框架-前传
自研框架-ioc
注解怎么创建?
ioc容器怎么拿到对象名?
package org.simpleframework.utils;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
@Slf4j
public class ClassUtil {
public static Set<Class<?>> exractPackClass(String packgeName){
获取当前线程的类加载器
ClassLoader classLoder = getClassLoder();
//通过类加载器获取到加载的资源
URL url = classLoder.getResource(packgeName.replace(".", "/"));
if (url == null) {
log.warn("获取不到url"+packgeName);
return null;
}
//依据不同资源类型,采用不用方式获取
Set<Class<?>> classSet = null;
//过滤出文件类型的资源
if(url.getProtocol().equalsIgnoreCase("file")){//对比不区分大小写
classSet = new HashSet<Class<?>>();
File packageDiectory = new File(url.getPath());
extractClassFile(classSet,packageDiectory,packgeName);
}
return classSet;
}
/***
* 递归获取目标package里面所有class文件
* @param classSet
* @param packageDiectory
* @param packgeName
*/
private static void extractClassFile(Set<Class<?>> classSet, File packageDiectory, String packgeName) {
//递归终止点,当递归到文件的时候就退出
if (!packageDiectory.isDirectory()){
return;
}
File[] files = packageDiectory.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
//ava中的isDirectory()是检查一个对象是否是文件夹。返回值是boolean类型的。如果是则返回true,否则返回false
if (file.isDirectory()){
return true;
}else {
//获取文件绝对值路劲
String absolutePath = file.getAbsolutePath();
if (absolutePath.endsWith(".class")){
//获取到绝对值路径后将通过反射加入
addToClassSet(absolutePath);
}
}
return false;
}
//将Class文件的绝对值路径。获取生成class对象,并放入classSet中
private void addToClassSet(String absolutePath) {
//从class文件绝对值路径中提取包类名
absolutePath = absolutePath.replace(File.separator, ".");
String className = absolutePath.substring(absolutePath.indexOf(packgeName));
className = className.substring(0,className.lastIndexOf("."));
//通过反射将对象名拿出来
Class<?> aClass = loadClass(className);
classSet.add(aClass);
}
});
if (files != null){
for (File f: files) {
extractClassFile(classSet, f, packgeName);
}
}
}
public static ClassLoader getClassLoder(){
//获取当前线程的类加载器
return Thread.currentThread().getContextClassLoader();
}
public static Class<?> loadClass(String className){
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//获取class类实例
public static <T> T newInstance(Class<?> clazz,boolean accessible) {
try {
Constructor declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(accessible);
return (T) declaredConstructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
根据实际路径获取class文件名存入set集合
容器单例输出安全吗?
开始创建容器吧!!
package org.simpleframework.core;
import com.sun.corba.se.impl.io.ValueUtility;
import com.sun.deploy.util.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.annotation.Compoment;
import org.simpleframework.core.annotation.Controller;
import org.simpleframework.core.annotation.Repository;
import org.simpleframework.core.annotation.Service;
import org.simpleframework.utils.ClassUtil;
import java.awt.*;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description:
* @author: zhangyihan
* @createDate: 2021-04-29 14:50
* @version: 1.0
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {
//检查容器是否被加载过
private boolean load = false;
/**
*获取bean实例
*
* @return
*/
public static BeanContainer getInstance(){
return ContainerHolder.HOLDER.instance;
}
//设置单例方法,将对象存入HOLDER
//使用枚举可以防止反射的入侵
private enum ContainerHolder{
HOLDER;
private BeanContainer instance;
ContainerHolder(){
instance =new BeanContainer();
}
}
/**
* 存放所有被注解配置过的目标对象Map
*/
private final Map<Class<?>,Object> beanMap= new ConcurrentHashMap();
/**
* 加载bean的注解列表
*
* @return
*/
private static final List<Class<? extends Annotation>> BEAN_ANNOTATION=
Arrays.asList(Compoment.class, Controller.class, Service.class, Repository.class);
//判断是否被加载
public boolean islocad(){
return load;
}
/***
*
* 扫描所有的类名
*
*/
public synchronized void localBeans(String packName){
if (islocad()){
log.warn("bean容器已经被加载过了");
return;
}
//获取当前线程的包名将class文件类名通过反射获取出来
Set<Class<?>> classSet = ClassUtil.exractPackClass(packName);
if (classSet == null || classSet.isEmpty()){
log.warn("找不到包类名"+packName);
return;
}
//将获取到的类名遍历出来
for (Class aClass:classSet){
//将标有注解的类循环遍历出来
for (Class<? extends Annotation> beanClass : BEAN_ANNOTATION)
{
//判断是否加了那四个注解
if (aClass.isAnnotationPresent(beanClass)){
//加了的话将类名本身作为减,实例作为值传入map之中
beanMap.put(aClass,ClassUtil.newInstance(aClass,true));
}
}
}
load = true ;
}
/***
* 添加一个class对象及其实例
*
*/
public Object addBean(Class<?> clazz,Object bean){
//map会返回传入值的对象
Object o = beanMap.put(clazz, bean);
return o;
}
/***
* 删除一个容器管理对象
*
*/
public Object removeBean(Class<?> clazz){
//根据名字删除,有值会返回删除值的类型,没就是null
return beanMap.remove(clazz);
}
/***
* 获取一个容器管理对象
*
*/
public Object getBean(Class<?> clazz){
return beanMap.get(clazz);
}
/***
* 获取容器管理所有对象
*
*/
public Set<Class<?>> getClasses(){
//根据名字删除,有值会返回删除值的类型,没就是null
return beanMap.keySet();
}
/***
* 获取容器bean集合
*
*/
public Set<Object> getBeansValues(){
//根据名字删除,有值会返回删除值的类型,没就是null
return new HashSet<>(beanMap.values());
}
/***
* 根据注解筛选出bean的class集合
*
*/
public Set<Class<?>> getClassByAnnotation(Class<? extends Annotation> annotation){
//获取beanMap的所有class对象
Set<Class<?>> keySet = getClasses();
if (keySet == null || "".equals(keySet)){
log.warn("nothing in beanMap");
return null;
}
//通过注解筛选出class对象,并添加到set里
Set<Class<?>> classSet = new HashSet<>();
for(Class<?> clazz :keySet){
if (clazz.isAnnotationPresent(annotation)){
classSet.add(clazz);
}
}
//统一返回值
return classSet.size() > 0? classSet:null;
}
/***
* 通过接口或者父类获取实现类或者子类的class集合,不包含本身
*
*/
public Set<Class<?>> getClassBySuper(Class<?> interfaceORClass){
//获取beanMap容器的所有class对象
Set<Class<?>> keySet = getClasses();
if (keySet == null || "".equals(keySet)){
log.warn("nothing in beanMap");
return null;
}
//通过注解筛选出class对象是否传入接口的子类,并添加到set里
Set<Class<?>> classSet = new HashSet<>();
for(Class<?> clazz :keySet){
//是否是传入接口的子类
if (interfaceORClass.isAssignableFrom(clazz) && !clazz.equals(interfaceORClass)){
classSet.add(clazz);
}
}
//统一返回值
return classSet.size() > 0? classSet:null;
}
}
实现容器的依赖注入
1.定义相关注解
2.创建注入类-DependencyInjector
package org.simpleframework.inject;
import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.inject.annotation.Autowired;
import org.simpleframework.utils.ClassUtil;
import java.lang.reflect.Field;
import java.util.Set;
@Slf4j
public class DependencyInjector {
//获取容器
private BeanContainer beanContainer;
public DependencyInjector() {
beanContainer = BeanContainer.getInstance();
}
/**
* 执行ioc依赖注入
*
*/
public void doIoc(){
if ((beanContainer.getClasses() == null || "".equals(beanContainer.getClasses()))){
log.warn("empty classet");
return;
}
//1.遍历Bean容器中所有的Class对象
for (Class<?> clazz :beanContainer.getClasses()){
//2.遍历Class对象的所有成员变量
// getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
Field[] fields = clazz.getDeclaredFields();
if (fields == null || "".equals(fields)){
continue;
}
for (Field field :fields){
//3.找出被Autowired标记的成员变量
if (field.isAnnotationPresent(Autowired.class)){
Autowired autowired = field.getAnnotation(Autowired.class);
String value = autowired.value();
//4.获取成员变量的类型
Class<?> aClass = field.getType();
//5.获取成员变量的类型在容器里面对饮的实例
Object fieldvalue = getFieldInstance(aClass,value);
if (fieldvalue == null){
throw new RuntimeException("运行autowired异常");
}else {
//6.通过反射将对应的成员变量实例注入到成员变量所在类的实例里
Object targetbean = beanContainer.getBean(clazz);
ClassUtil.setField(field,targetbean,fieldvalue,true);
}
}
}
}
}
/**
*获取成员变量获取的实例
* @param aClass
* @return
*/
private Object getFieldInstance(Class<?> aClass,String value) {
Object bean =beanContainer.getBean(aClass);
//判断变量是否为空,为空是类,不为空是接口
if (bean != null){
//类直接返回
return bean;
}else {
//接口获取实现类
Class<?> impl = getImpl(aClass,value);
if (impl != null){
return beanContainer.getBean(impl);
}else {
return null;
}
}
}
/**
* 获取接口实现类
* @param bean
* @return
*/
private Class<?> getImpl(Class<?> bean,String value) {
//调用实现接口子类
Set<Class<?>> classBySuper = beanContainer.getClassBySuper(bean);
//是否有这个实现子类
if (!(classBySuper == null || "".equals(classBySuper))){
//是否设置默认值输出实现类
if ((classBySuper == null || "".equals(value))){
//只有一个实现类
if (classBySuper.size() == 1){
//迭代输出
return classBySuper.iterator().next();
}else {
//多个实现类,抛出异常让用户自己选择加out注解
throw new RuntimeException("多个实现类"+bean.getName());
}
}else {
for (Class<?> aClass : classBySuper){
if (value.equals(aClass.getSimpleName())){
return aClass;
}
}
}
}
return null;
}
}
工具类创建属性
/***
* 设置类属性值
* @param field 成员变量
* @param target 类实例
* @param value 成员变量的值
* @param accessible 是否允许有私自属性
*/
public static void setField(Field field, Object target, Object value, Boolean accessible)
{
field.setAccessible(accessible);
try {
//给target实例里面的field成员变量设置value的值
field.set(target,value);
}catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
使用
当有两类时就会报出有多个实现类的错误,需要指定实现
beanPostProcessors使用
beanPostProcessors是什么?
bean的后置处理器,bean初始化之前干点什么,之后又干点什么,在不影响代码的情况下创建类似于插件的功能,aop的实现原理也是如此。
创建一个现实类
创建一个list集合存放处理器
判断这个类是否实现了beanPostProcessors接口
将list里面的beanPostProcessors遍历出来一一实现
运行测试,再多加一个类也是如此,不改变代码加功能
Aop的代理逻辑也是在beanPostProcessors实现