1 聊聊Ioc,Di,Mvc,Aop
不想看下面内容的,直接上代码连接,以下代码都有注释
传送门
1.1 看启动项
我们先来看看启动项
package com.tian;import com.tian.springframework.annotation.SpringBootApplication;
import com.tian.springframework.config.SpringApplication;
import com.tian.springframework.annotation.ServletLoadOnStartUp;/*** @Author: zlx* @Date: 2020/4/14 1:30* @Desc:*/
@SpringBootApplication
@ServletLoadOnStartUp(loadOnStartUp = 1)
public class Application {public static void main(String[] args) throws Exception{SpringApplication.run(Application.class,args);}
}
注意:启动项有个run方法,我们来看看run方法是干嘛的
package spring.framework;import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import spring.Application;
import spring.framework.config.PropertiesConfig;
import spring.framework.webmvc.serlvet.DispatcherServlet;/*** zlx* */
public class SpringApplication {// 用来启动public static void run(Class<Application> applicationClass, String[] args) throws LifecycleException {long start = System.currentTimeMillis();// 开启TomcatTomcat tomcat = new Tomcat();// 用来读取配置文件PropertiesConfig propertiesConfig = new PropertiesConfig();// 设置端口tomcat.setPort(Integer.valueOf(propertiesConfig.properties.getProperty("server.port")));// 设置contextPath和路径Context context = tomcat.addContext(propertiesConfig.properties.getProperty("server.path"), null);// 配置servlet,此处相当于初始化了整个spring上下文tomcat.addServlet(propertiesConfig.properties.getProperty("server.path"), "111", new DispatcherServlet(applicationClass));context.addServletMappingDecoded("/", "111");// 启动tomcattomcat.start();long end = System.currentTimeMillis();System.out.println("启动完成,共使用了:" + (end - start) + "ms");// 进入监听状态,如果不进入监听状态,启动tomat后就会关闭tomcattomcat.getServer().await();}
}
概括来说分为以下4个步骤
(1)开启Tomcat
(2)读取配置文件
(3)开启serlvet(这里我们用到了前端控制DispatcherServlet,用来请求分发,下面将用来介绍)
(4)tomcat监听
1.1.1 读取配置
// 用来读取配置文件PropertiesConfig propertiesConfig = new PropertiesConfig();
这条代码用来读取配置文件的信息,我们来看看做了什么操作
package spring.framework.config;import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;/*** 封装一个对象用来读取配置文件*/
public class PropertiesConfig {// 用来读取配置文件public Properties properties = new Properties();public PropertiesConfig() {initProperties();}/*** 读取配置文件*/private void initProperties() {// 通过文件流读取properties配置文件InputStream is = this.getClass().getClassLoader().getResourceAsStream("application.properties");if (is != null){try {properties.load(is);} catch (IOException e) {e.printStackTrace();} finally {try {is.close();} catch (IOException e) {e.printStackTrace();}}}}public Properties getProperties(){return this.properties;}}
代码中我们发现,通过url指定配置文件所在的路径,通过流的形式被properties加载。
接下来我们就可以配置的我们tomcat的启动信息了
1.1.2 开启servlet
tomcat可以添加servlet,相当于SSM项目中的web.xml配置指定serlvet,在这里我们注册一个(前端控制器,用来请求分发),我们来看看servlet,有什么功能
package spring.framework.webmvc.serlvet;import spring.Application;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 前端控制器*/
public class DispatcherServlet extends HttpServlet{public DispatcherServlet(Class<Application> applicationClass) {}@Overridepublic void init() {}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doGet(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
**init方法:**用来初始化,我们的IOC、AOP、MVC,DI都是这里初始化的
doPost接收Post请求,用于请求分发,涉及到MVC的内容
doGet接收Get请求,用于请求分发,涉及到MVC的内容
Ioc的初始化
我们知道在面向对象设计的软件系统中,它的底层都是由N个对象构成的,各个对象之间通过相互合作,最终实现系统地业务逻辑[1]。
我们所说的Ioc就是项目中对象(bean)的容器,我们可以一次性加载所有项目的对象,放在一个容器中作为第三者,实现了项目的解耦。我们最常用的方法就是从容器中获取对象bean。
下面我们分析如何获取bean
首先我们来看一张图
(1)通过一个ApplicationContext,作为spring的上下文,用来ioc到di和aop
(2)通过BeanDenfitionReader读取项目中所有需要的类 解析为BeanDefinition,在存到一个List(registerBeanClasses)中
(3)遍历registerBeanClasses,封装成BeanDenfinition,注意这里
接口、抽象类、不是@Controller,不是@Service的类不要封装,如果这个类有接口,那么就把它(实现类)封装成BeanDenfinition,factoryName是他接口的全类名,bean的id还是他本身的全类名(主要是解决依赖注意DI的问题)
(4)将BeanDenfinition放入一个第一层的伪IOC容器中beanDefinitionMap,注意这里有一层二对一的关系,我们会将factoryName(bean的Id)和BeanClassName绑定一个bean
(5)从BeanDefinitionMap中拿出来所有的bean,判断一下这个bean是不是懒加载,懒加载就不会进行初始化,只有在用到的时候才会初始化。
(6)初始化Bean,根据BeanName,getBean,这个主要完成两件事情
1.创建实例
2.依赖注入
(7)根据BeanName获取BeanDefinition信息,反射创建实例instance,将实例放进第二层缓存factoryBeanObjectCache的Map中,Key是全类名,Value是instance实例,然后封装成BeanWrapper(主要有Class和实例)。
(8)BeanWrapper放进Ioc容器中(factoryBeanInstanceCache),也就是第三层缓存,key是全类名,value是BeanWrapper对象
到这里,我们的Ioc容器初始化成功,剩下的就是DI和Aop,在DI之前我们先是有AOP的初始化
前端控制器代码
package spring.framework.webmvc.serlvet;import lombok.extern.slf4j.Slf4j;
import spring.Application;
import spring.framework.annotation.ServletLoadOnStartUp;
import spring.framework.annotation.SpringBootApplication;
import spring.framework.config.PropertiesConfig;
import spring.framework.context.ApplicationContext;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 前端控制器*/
@Slf4j
public class DispatcherServlet extends HttpServlet{private Class<?> applicationClass;/*** spring的上下文*/private ApplicationContext applicationContext;/*** 配置文件*/public static PropertiesConfig propertiesConfig;public DispatcherServlet(PropertiesConfig propertiesConfig, Class<?> applicationClass) {DispatcherServlet.propertiesConfig = propertiesConfig;this.applicationClass = applicationClass;ServletLoadOnStartUp annotation = this.applicationClass.getAnnotation(ServletLoadOnStartUp.class);// 用ServletLoadOnStartUp注解是否初始化if (annotation != null && annotation.loadOnStartUp() > 0){this.init();}}@Overridepublic void init() {if (this.applicationClass.isAnnotationPresent(SpringBootApplication.class)){this.applicationContext = new ApplicationContext(this.applicationClass);// 初始化MVC// initStrategies(this.applicationContext);log.error("容器初始化完成了。。。。。。");}}/** 初始化MVC九大部件* @param applicationContext*/private void initStrategies(ApplicationContext applicationContext) {}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doGet(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
可以看到入口是ApplicationContext
ApplicationContext 代码
package spring.framework.context;import lombok.extern.slf4j.Slf4j;
import spring.framework.annotation.Autowired;
import spring.framework.beans.BeanFactory;
import spring.framework.beans.BeanWrapper;
import spring.framework.beans.NoSuchBeanDefinitionException;
import spring.framework.beans.UnsatisfiedDependencyException;
import spring.framework.beans.factory.DefaultListableBeanFactory;
import spring.framework.beans.factory.config.BeanDefinition;
import spring.framework.beans.factory.support.BeanDefinitionReader;
import spring.framework.context.support.AbstractApplicationContext;
import spring.framework.webmvc.serlvet.DispatcherServlet;import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** spring上下文*/
@Slf4j
public class ApplicationContext extends DefaultListableBeanFactory implements BeanFactory {private Class<?> applicationClass;private BeanDefinitionReader beanDefinitionReader;/*** 单例池*/private Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<String, Object>();/*** IOC容器*/private Map<String, BeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<String, BeanWrapper>();public ApplicationContext(Class<?> applicationClass) {this.applicationClass = applicationClass;try {refresh();} catch (Exception e) {System.out.println("初始IOC和DI异常");}}@Overridepublic void refresh() {try {// 初始化BeanDefitionReaderbeanDefinitionReader = new BeanDefinitionReader(DispatcherServlet.propertiesConfig.properties.getProperty("scanPackage"));// 扫描包下的所有全类名,把他们封装成BeanDefinitionList<BeanDefinition> beanDefinitions = beanDefinitionReader.loadBeanDefinitions();// 注册,把配置信息放到容器里面(伪IOC容器)doRegisterBeanDefinition(beanDefinitions);// 把不是懒加载的类给初始化doAutowired();}catch (Exception ex){log.error("异常",ex);}}/*** DI 依赖注入*/private void doAutowired() {for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {String beanName = beanDefinitionEntry.getKey();//非懒加载进行注入if(!beanDefinitionEntry.getValue().isLazyInit()){getBean(beanName);}}}/** beanDefinition存入Map* @param beanDefinitions* @throws Exception*/private void doRegisterBeanDefinition(List<BeanDefinition> beanDefinitions) throws Exception {for (BeanDefinition beanDefinition : beanDefinitions){// bean的Id不能重复,所以这也是我们写实现层,控制层的ClassName不能一样的原因if (super.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())){throw new Exception("factoryBeanName: " + beanDefinition.getFactoryBeanName() + "已经存在容器中了");}// 这里我们有一层二对一的关系,通过bean的Id和全类名映射一个beansuper.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);super.beanDefinitionMap.put(beanDefinition.getBeanClassName(),beanDefinition);}}/** 根据bean的Id 获取bean* @param beanName * @return*/public Object getBean(String beanName) {try{BeanDefinition beanDefinition = super.beanDefinitionMap.get(beanName);if (beanDefinition == null){throw new NoSuchBeanDefinitionException("无法从beanDefinitionMap中找到BeanDefinition");}Object instance = null;// 1.初始化instance = instantiateBean(beanName,beanDefinition);// 2.把这个对象封装到BeanWrapper中BeanWrapper beanWrapper = new BeanWrapper(instance);// 3. 放入真正的IOC容器this.factoryBeanInstanceCache.put(beanName,beanWrapper);// 4.依赖注入// 4.依赖注入populateBean(beanName,beanWrapper);}catch (Exception ex){}return null;}/** DI(依赖注入)* @param beanName* @param beanWrapper*/private void populateBean(String beanName, BeanWrapper beanWrapper) {}/** 用一种类似与懒加载的方式,先从二级缓存取,如果没有就实例化对象* @param beanName* @param beanDefinition* @return*/private Object instantiateBean(String beanName, BeanDefinition beanDefinition) {try {// 根据BeanDefinition的全类名拿到要生成对象的类String className = beanDefinition.getBeanClassName();// 生成对象Object instance = null;// 验证if (this.factoryBeanObjectCache.containsKey(beanName)){instance = this.factoryBeanObjectCache.get(beanName);}else if (this.factoryBeanObjectCache.containsKey(beanDefinition.getFactoryBeanName())){instance = this.factoryBeanObjectCache.get(beanDefinition.getFactoryBeanName());}else {Class<?> clazz = Class.forName(className);boolean anAbstract = Modifier.isAbstract(clazz.getModifiers());// 如果是抽象类则不能实例化if (anAbstract) return null;// 验证isPopulateByFields(clazz);instance = clazz.newInstance();/* //处理aopAdviceSupport adviceSupport = instantionAopConfig(beanDefinition);adviceSupport.setTargetClass(clazz);adviceSupport.setTarget(instance);if(adviceSupport.getPointCutPattern() != null && adviceSupport.matchPointCut()){instance = createProxy(adviceSupport).getProxy();}*/// 放入二级缓存this.factoryBeanObjectCache.put(beanName,instance);this.factoryBeanObjectCache.put(beanDefinition.getBeanClassName(),instance);}}catch (Exception ex){log.error("实例化对象异常",ex);}return null;}/** 这个类下面如果要是有注入的类没有在伪Ioc容器中,beanDenfinitonMap,抛出异常* @param clazz*/private void isPopulateByFields(Class<?> clazz) {Field[] fields = clazz.getDeclaredFields();for (Field item:fields) {if (item.isAnnotationPresent(Autowired.class)){Class<?> fieldType = item.getType();BeanDefinition beanDefinition = this.beanDefinitionMap.get(fieldType.getName());if (beanDefinition == null){throw new UnsatisfiedDependencyException("在 '"+ clazz+ "' 类中的属性 '" + fieldType.getName() + "' 不存在容器中");}}}}/** 根据类,获取Bean* @param beanClass * @return*/public Object getBean(Class<?> beanClass) {return getBean(beanClass.getName());}
}
伪Ioc容器
package spring.framework.beans.factory;import spring.framework.beans.factory.config.BeanDefinition;
import spring.framework.context.support.AbstractApplicationContext;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @Author: tian* @Date: 2020/4/8 17:46* @Desc:*/
public class DefaultListableBeanFactory extends AbstractApplicationContext {//存储注册信息的BeanDefinition,伪IOC容器protected final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();}
Ioc顶层设计
package spring.framework.context.support;/*** @Author: zlx* @Date: 2020/8/15 11:56* @Desc: IOC容器实现的顶层设计*/
public class AbstractApplicationContext {//受保护,只提供给子类重写(此处是IOC和DI的初始化)public void refresh() throws Exception{}
}
BeanFactory的工厂
package spring.framework.beans;/*** @Author: zlx* @Date: 2020/8/15 11:39* @Desc: 单例工厂的顶层设计*/
public interface BeanFactory {/*** 根据beanName从IOC容器中获得一个实例bean* @param beanName* @return*/Object getBean(String beanName);Object getBean(Class<?> beanClass);
}
beanDefinitionReader 读取项目包名下符合规则的类名(这里只要有@Controller和@Service下的类),把全类名和类名小写封装成BeanDenfiniton(用于构件伪Ioc容器)。
package spring.framework.beans.factory.support;import org.apache.jasper.tagplugins.jstl.core.Url;
import spring.framework.annotation.Controller;
import spring.framework.annotation.Service;
import spring.framework.beans.factory.config.BeanDefinition;import java.io.File;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;public class BeanDefinitionReader {/*** 存储全类名*/private List<String> registerBeanClasses = new ArrayList<String>();public BeanDefinitionReader(String packageName) {// 扫描当前包下的所有类,将其全类名放到一个List中doScanner(packageName);}/** 扫描当前包名下的所有类名,存到List中* @param packageName*/private void doScanner(String packageName) {URL url = this.getClass().getResource("/" + packageName.replaceAll("\\.","/"));File files = new File(url.getFile());for (File file:files.listFiles()){//if (file.isDirectory()){doScanner(packageName + "." + file.getName());}else {if (!file.getName().endsWith(".class")) continue;String fileName = packageName + "." +file.getName().replace(".class","");registerBeanClasses.add(fileName);}}}/** 根据全类名 封装成BeanDefinition* @return* @throws ClassNotFoundException*/public List<BeanDefinition> loadBeanDefinitions() throws ClassNotFoundException {List<BeanDefinition> result = new ArrayList<BeanDefinition>();for (String className:registerBeanClasses){Class<?> beanClass = Class.forName(className);// 1.接口不要// 2 抽象类不要// 3.没有Controller注解不要// 4.没有Service注解不要if(!beanClass.isInterface() && !(Modifier.isAbstract(beanClass.getModifiers())) &&(beanClass.isAnnotationPresent(Controller.class) || beanClass.isAnnotationPresent(Service.class)) ){// 创建BeanDenfinition,bean的id是他类名的首字母小写,beanClassName是全类名BeanDefinition beanDefinition = doCreateBeanDefinition(toLowerFirsetCase(beanClass.getSimpleName()),beanClass.getName());result.add(beanDefinition);// 注意这里这个类如果是实现类才会进行// 获取这个类的接口 把他的接口的实现类放进来,但是最终只会保留一个Class<?>[] interfaces = beanClass.getInterfaces();for (Class<?> anInterfaces : interfaces){// bean的id 是他的接口的全类名,beanClassName是他(实现类)的全类名result.add(doCreateBeanDefinition(anInterfaces.getName(),beanClass.getName()));}}}return result;}/** 创建BeanDenfinition* @param factoryBeanName bean的id* @param beanClassName 全类名* @return*/private BeanDefinition doCreateBeanDefinition(String factoryBeanName,String beanClassName) {BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setFactoryBeanName(factoryBeanName);beanDefinition.setBeanClassName(beanClassName);return beanDefinition;}/*** 首字母转小写* @param beanName* @return*/private String toLowerFirsetCase(String beanName){char[] chars = beanName.toCharArray();chars[0] += 32;return String.valueOf(chars);}
}
Aop的初始化(简单版的)
先来看看自己定义的切面类
package com.gupaoedu.vip.demo.aspect;import lombok.extern.slf4j.Slf4j;/*** Created by Tom.*/
@Slf4j
public class LogAspect {//在调用一个方法之前,执行before方法public void before(){//这个方法中的逻辑,是由我们自己写的log.info("Invoker Before Method!!!");}//在调用一个方法之后,执行after方法public void after(){log.info("Invoker After Method!!!");}public void afterThrowing(){log.info("出现异常");}}
我们先来看张图
回看代码,之前AOP的代码被隐藏了
/** 用一种类似与懒加载的方式,先从二级缓存取,如果没有就实例化对象* @param beanName* @param beanDefinition* @return*/private Object instantiateBean(String beanName, BeanDefinition beanDefinition) {try {// 根据BeanDefinition的全类名拿到要生成对象的类String className = beanDefinition.getBeanClassName();// 生成对象Object instance = null;// 验证if (this.factoryBeanObjectCache.containsKey(beanName)){instance = this.factoryBeanObjectCache.get(beanName);}else if (this.factoryBeanObjectCache.containsKey(beanDefinition.getFactoryBeanName())){instance = this.factoryBeanObjectCache.get(beanDefinition.getFactoryBeanName());}else {Class<?> clazz = Class.forName(className);boolean anAbstract = Modifier.isAbstract(clazz.getModifiers());// 如果是抽象类则不能实例化if (anAbstract) return null;// 验证isPopulateByFields(clazz);instance = clazz.newInstance();/* //处理aopAdviceSupport adviceSupport = instantionAopConfig(beanDefinition);adviceSupport.setTargetClass(clazz);adviceSupport.setTarget(instance);if(adviceSupport.getPointCutPattern() != null && adviceSupport.matchPointCut()){instance = createProxy(adviceSupport).getProxy();}*/// 放入二级缓存this.factoryBeanObjectCache.put(beanName,instance);this.factoryBeanObjectCache.put(beanDefinition.getBeanClassName(),instance);}}catch (Exception ex){log.error("实例化对象异常",ex);}return null;}
我们先来看看
AdviceSupport adviceSupport = instantionAopConfig(beanDefinition);
在这之前,我们回到AOP的图片,看看AdviceSupport 是什么东西
package com.gupaoedu.vip.spring.framework.aop.support;import com.gupaoedu.vip.spring.framework.aop.aspect.GPAdvice;
import com.gupaoedu.vip.spring.framework.aop.config.GPAopConfig;import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** */
public class GPAdvisedSupport {// 存储切面的内容private GPAopConfig config;// 要代理的类名private Class targetClass;// 要代理的对象private Object target;// 判断当前类是否符合切面类的定义private Pattern pointCutClassPattern;// 封装当前类下的方法和代理方法的映射private Map<Method,Map<String, GPAdvice>> methodCache;//解析读取出来的配置信息//肯定又要用到正则public GPAdvisedSupport(GPAopConfig config) {this.config = config;}public Class getTargetClass() {return targetClass;}public void setTargetClass(Class targetClass) {this.targetClass = targetClass;parse();}private void parse() {String pointCut = config.getPointCut().replaceAll("\\.","\\\\.").replaceAll("\\\\.\\*",".*").replaceAll("\\(","\\\\(").replaceAll("\\)","\\\\)");//pointCut=public .* com.gupaoedu.vip.demo.service..*Service..*(.*)String pointCutForClassRegex = pointCut.substring(0,pointCut.lastIndexOf("\\(") - 4);//提取Class的全名 com.gupaoedu.vip.demo.service..*ServicepointCutClassPattern = Pattern.compile(pointCutForClassRegex.substring(pointCutForClassRegex.lastIndexOf(" ") + 1));try {// 思想从来没有变// 保存方法和通知的关系methodCache = new HashMap<Method, Map<String, GPAdvice>>();Pattern pointCutPattern = Pattern.compile(pointCut);//com.gupaoedu.vip.demo.aspect.LogAspectClass aspectClass = Class.forName(this.config.getAspectClass());Map<String,Method> aspectMethods = new HashMap<String, Method>();for (Method method : aspectClass.getMethods()) {aspectMethods.put(method.getName(),method);}// 遍历当前类下的所有方法for (Method method : this.targetClass.getMethods()) {String methodString = method.toString();if(methodString.contains("throws")){methodString = methodString.substring(0,methodString.lastIndexOf("throws")).trim();}Matcher matcher = pointCutPattern.matcher(methodString);if(matcher.matches()){Map<String,GPAdvice> adivces = new HashMap<String, GPAdvice>();//前置通知if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))){adivces.put("before",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectBefore())));}//前置通知if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))){adivces.put("after",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfter())));}//异常通知if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))){adivces.put("afterThrowing",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfterThrow())));}methodCache.put(method,adivces);}}}catch (Exception e){e.printStackTrace();}}public boolean ponitCutMatch() {return pointCutClassPattern.matcher(this.targetClass.getName()).matches();}public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}public Map<String,GPAdvice> getAdices(Method method, Class targetClass) throws Exception {Map<String,GPAdvice> cache = methodCache.get(method);//技巧:代理以后的方法if(null == cache){Method m = targetClass.getMethod(method.getName(),method.getParameterTypes());cache = methodCache.get(m);this.methodCache.put(m,cache);}return cache;}
}
再来看看AopConfig是怎么存储切面内容的
package com.gupaoedu.vip.spring.framework.aop.config;import lombok.Data;/*** Created by zlx.*/
@Data
public class GPAopConfig {// 切入点(pointCut=public .* com.gupaoedu.vip.demo.service..*Service..*(.*))private String pointCut;// 切面类(用来获取切面下的所有加强方法)private String aspectClass;// 前置通知(前置加强)private String aspectBefore;// 后置通知(后置加强)private String aspectAfter;// 环绕通知(环绕加强)private String aspectAfterThrow;// 异常通知(异常加强)private String aspectAfterThrowingName;
}
看看Aop封装代理内容
package com.gupaoedu.vip.spring.framework.aop.aspect;import java.lang.reflect.Method;/** 会把这个对象封装成一个“增强方法名” -> 增强方法GPAdvice 的映射* Created by zlx.*/public class GPAdvice {// 要增强方法所在类名private Object aspect;// 要增强的方法private Method adivceMethod;// 抛出的异常名称private String throwName;public GPAdvice(Object aspect, Method adviceMethod) {this.aspect = aspect;this.adivceMethod = adviceMethod;}public Object getAspect() {return aspect;}public Method getAdivceMethod() {return adivceMethod;}public String getThrowName() {return throwName;}public void setThrowName(String throwName) {this.throwName = throwName;}
}
封装好这些对象后,我们看怎么处理以上内容的
config.setTargetClass(clazz);
config.setTarget(instance);
以上两行代码用于封装AOP的代理到一个对象()
核心代码块是parse()
private void parse() {// 1.用于查找当前类的所有方法符合切面类的定义String pointCut = config.getPointCut().replaceAll("\\.","\\\\.").replaceAll("\\\\.\\*",".*").replaceAll("\\(","\\\\(").replaceAll("\\)","\\\\)");// 2.用于查找当前类是否符合切面类,如果是,就为这个类生成代理对象//pointCut=public .* com.gupaoedu.vip.demo.service..*Service..*(.*)String pointCutForClassRegex = pointCut.substring(0,pointCut.lastIndexOf("\\(") - 4);//提取Class的全名 com.gupaoedu.vip.demo.service..*ServicepointCutClassPattern = Pattern.compile(pointCutForClassRegex.substring(pointCutForClassRegex.lastIndexOf(" ") + 1));try {// 3.处理切面类(LogAspect)下所有方法与跟GPAdvice的映射简称(aspectMethods)//com.gupaoedu.vip.demo.aspect.LogAspectClass aspectClass = Class.forName(this.config.getAspectClass());Map<String,Method> aspectMethods = new HashMap<String, Method>();for (Method method : aspectClass.getMethods()) {aspectMethods.put(method.getName(),method);}// 4.扫描当前类下所有方法名,符合方法1的方法就把它加入到(当前方法名跟aspectMethods的映射)简称methodCache// 至于这个methodCache,我们将会在生成代理方法的时候用到。// 思想从来没有变// 保存方法和通知的关系methodCache = new HashMap<Method, Map<String, GPAdvice>>();//Pattern pointCutPattern = Pattern.compile(pointCut);// 遍历当前类下的所有方法for (Method method : this.targetClass.getMethods()) {String methodString = method.toString();// 如果符合异常通知if(methodString.contains("throws")){methodString = methodString.substring(0,methodString.lastIndexOf("throws")).trim();}Matcher matcher = pointCutPattern.matcher(methodString);// 如果方法1下的所有通知if(matcher.matches()){Map<String,GPAdvice> adivces = new HashMap<String, GPAdvice>();//前置通知if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))){adivces.put("before",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectBefore())));}//后置通知if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))){adivces.put("after",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfter())));}//异常通知if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))){adivces.put("afterThrowing",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfterThrow())));}// 完成隐射methodCache.put(method,adivces);}}}catch (Exception e){e.printStackTrace();}}
接下来就是生成代理对象了
//判断要不要创建代理类 当前类符合切面类if(config.ponitCutMatch()){instance = new GPJdkDynamicAopProxy(config).getProxy();}
package com.gupaoedu.vip.spring.framework.aop;import com.gupaoedu.vip.spring.framework.aop.aspect.GPAdvice;
import com.gupaoedu.vip.spring.framework.aop.support.GPAdvisedSupport;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;/*** Created by Tom.*/
public class GPJdkDynamicAopProxy implements InvocationHandler{// 维持对一个要代理内容的对象private GPAdvisedSupport config;public GPJdkDynamicAopProxy(GPAdvisedSupport config) {this.config = config;}public Object getProxy() {// 使用JDK的动态代理模式return Proxy.newProxyInstance(this.getClass().getClassLoader(),this.config.getTargetClass().getInterfaces(),this);}/** 增强的代理方法* 这里只要进入了代理对象的方法,就会进入到这里,我们就可以在这里完成动态代理了* @param proxy* @param method* @param args* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 1. 首先我们根据方法名从methodCache拿到GPAdvice//method 用户调用的方法//args 实参Map<String,GPAdvice> advices = this.config.getAdices(method,this.config.getTargetClass());Object returnValue;// 2.执行前置通知// 根据通知的方法名拿到advice,advice里边有增强的方法和对象invokeAdvice(advices.get("before"));try {// 3.用于执行当前类下的原有方法returnValue = method.invoke(this.config.getTarget(), args);}catch (Exception e){// 3.执行异常通知invokeAdvice(advices.get("afterThrowing"));e.printStackTrace();throw e;}// 4.执行后置通知invokeAdvice(advices.get("after"));return returnValue;}/** 执行切面类下的方法** @param advice*/private void invokeAdvice(GPAdvice advice) {try {advice.getAdivceMethod().invoke(advice.getAspect());} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}
}
分析以上内容
(1) 用于查找当前类的所有方法符合切面类的定义
(2)处理切面类(LogAspect)下所有方法与跟GPAdvice的映射简称(aspectMethods)
(4)扫描当前类下所有方法名,符合方法1的方法就把它加入到(当前方法名跟aspectMethods的映射)简称methodCache
(5)用于查找当前类是否符合切面类,如果是,就为这个类生成代理对象
(5)生成代理对象具体流程如下
1.反射拿到方法,从methodCache拿到aspectMethods,通过前置方法名拿到GPAdvice,再用反射执行GPAdvice里边的找到要执行的切面类下的method。
Aop的初始化(真实MINI版)
事实上Spring并不会通过一个简单的Map存储Advice,而是通过一层层的封装,通过这一层层的封装,可以获取原有方法的参数。
看完了Advice,我们重新看看parase()
/*** 组装通知*/private void parse() {/*spring中的切入点表达式 execution (public * spring.service.impl..*.*(..))public为修饰符 ;第一个*号:表示返回类型,*号表示所有的类型;包名表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包 spring.service.impl包、子孙包下所有类的方法。第二个*号:表示类名,*号表示所有的类。*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。*/try {if (this.aopConfig == null || this.aopConfig.getPointCut() == null) {return;}//PonintCut 表达式解析为正则表达式(方法名)String pointCut = this.aopConfig.getPointCut().replaceAll("\\.","\\\\.").replaceAll("\\\\.\\*",".*").replaceAll("\\(","\\\\(").replaceAll("\\)","\\\\)");String pointCutForClassRegex = pointCut.substring(0, pointCut.lastIndexOf("\\(") - 4);// 判断类名是否要加强pointCutPattern = Pattern.compile("class " + pointCutForClassRegex.substring(pointCutForClassRegex.lastIndexOf(" ") + 1));// 这个正则是用来判断方法名是否符合要增强的Pattern pattern = Pattern.compile(pointCut);// 将增强的方法放到一个Map里面Class<?> aspectClass = Class.forName(this.aopConfig.getAspectClass());Map<String,Method> methodAdvices = new HashMap<String, Method>();for (Method method : aspectClass.getMethods()){methodAdvices.put(method.getName(),method);}for (Method item: this.targetClass.getMethods()) {// 获取方法名String methodName = item.toString();if (methodName.contains("throws")) {methodName = methodName.substring(0,methodName.lastIndexOf("throws")).trim();}if (pattern.matcher(methodName).matches()) {// 因为这几种通知执行的顺序是不会变的,所以这里用一个LinkedList来存储,依次是before、after、afterThrowing、afterRetuingList<Object> advices = new LinkedList<Object>();// 1.前置通知`if (this.aopConfig.getAspectBefore() != null) {advices.add(new MethodBeforeAdviceInterceptor(methodAdvices.get(this.aopConfig.getAspectBefore().getName()), aspectClass.newInstance()));}// 2.后置通知if (!(null == this.aopConfig.getAspectAfter())) {advices.add(new AspectAfterAdvice(methodAdvices.get(this.aopConfig.getAspectAfter().getName()), aspectClass.newInstance()));}// 3.异常通知if (!(null == this.aopConfig.getAspectAfterThrowing() || "".equals(this.aopConfig.getAspectAfterThrowing()))) {AspectJAfterThrowingAdvice throwingAdvice =new AspectJAfterThrowingAdvice(methodAdvices.get(this.getAopConfig().getAspectAfter().getName()),aspectClass.newInstance());throwingAdvice.setThrowName("java.lang.Exception");advices.add(throwingAdvice);}// 4.最终返回通知if (!(null == this.aopConfig.getAspectAfterReturning() || "".equals(this.aopConfig.getAspectAfterReturning()))) {advices.add(new AfterReturningAdviceInterceptor(methodAdvices.get(this.aopConfig.getAspectAfterReturning().getName()), aspectClass.newInstance()));}methodCache.put(item, advices);}}}catch (Exception ex){}}
package spring.framework.aop.adapt;import spring.framework.aop.advice.Advice;import java.lang.reflect.Method;/*** 抽象拦截器*/
public class AbstractAspectAdvice implements Advice {/*** 要增强的方法(切面类)*/private Method aspectMethod;/*** 要增强的对象(切面类)*/private Object aspectTarget;public AbstractAspectAdvice(Method aspectMethod, Object aspectTarget) {this.aspectMethod = aspectMethod;this.aspectTarget = aspectTarget;}
}
下面我们来看看拦截器,分别有
1.前置通知
2.后置通知
3.异常通知
4.返回通知
package spring.framework.aop.adapt;import spring.framework.aop.ReflectiveMethodInvocation;
import spring.framework.aop.advice.Advice;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.Method;/*** 前置拦截器*/
public class MethodBeforeAdviceInterceptor extends AbstractAspectAdvice implements MethodInterceptor {public MethodBeforeAdviceInterceptor(Method aspectMethod, Object aspectTarget) {super(aspectMethod, aspectTarget);}@Overridepublic Object invoke(ReflectiveMethodInvocation methodInvocation) throws Exception {return null;}
}
package spring.framework.aop.adapt;import spring.framework.aop.ReflectiveMethodInvocation;
import spring.framework.aop.interceptor.JoinPoint;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.Method;/*** 后置拦截器*/
public class AspectAfterAdvice extends AbstractAspectAdvice implements MethodInterceptor {private JoinPoint joinPoint;public AspectAfterAdvice(Method method, Object o) {super(method,o);}@Overridepublic Object invoke(ReflectiveMethodInvocation methodInvocation) throws Exception {return null;}
}
package spring.framework.aop.adapt;import spring.framework.aop.ReflectiveMethodInvocation;
import spring.framework.aop.interceptor.JoinPoint;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.Method;/*** 返回通知拦截器(具体拦截器)*/
public class AfterReturningAdviceInterceptor extends AbstractAspectAdvice implements MethodInterceptor {/*** 封装参数*/private JoinPoint joinPoint;public AfterReturningAdviceInterceptor(Method method, Object o) {super(method,o);}@Overridepublic Object invoke(ReflectiveMethodInvocation methodInvocation) throws Exception {return null;}
}
package spring.framework.aop.adapt;import lombok.Data;import java.lang.reflect.Method;/*** 异常拦截器*/
public class AspectJAfterThrowingAdvice extends AbstractAspectAdvice{/*** 异常名称*/private String throwName;public AspectJAfterThrowingAdvice(Method aspectMethod, Object aspectTarget) {super(aspectMethod, aspectTarget);}public String getThrowName() {return throwName;}public void setThrowName(String throwName) {this.throwName = throwName;}
}
处理完拦截器后,要开始处理AOP了,这里使用JDK的动态代理实现
package spring.framework.aop;import org.omg.CORBA.SystemException;
import org.omg.CORBA.portable.InputStream;
import org.omg.CORBA.portable.InvokeHandler;
import org.omg.CORBA.portable.OutputStream;
import org.omg.CORBA.portable.ResponseHandler;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;/*** JDK动态代理,代理是接口,* JDK动态代理原理,* 1.用过InvocationHandler接口创建自己的调用处理器* 2.通过Proxy指定类的加载器,和一组interface来创建动态代理* 3.通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型* 4.通过构造函数创建代理类的实例,构造时调用处理器对象作为参数输入* JDK动态代理是面向接口的代理模式 ,如果代理目标没有接口,spring也无为力* 处理器的invoke方法重写了AOP的增强方法* 由于Java的单继承,动态生成的代理类已经继承了Proxy类的,就不能再继承其他类* 所以只能实现代理类接口的形式,所以JDK的动态代理必须要有 接口*/
public class JDKDynamicAopProxy implements InvocationHandler, AopProxy {private AdviceSupport advised;public JDKDynamicAopProxy(AdviceSupport adviceSupport){this.advised = adviceSupport;}@Overridepublic Object getProxy() throws Exception {return this.getProxy(this.advised.getTargetClass().getClassLoader());}@Overridepublic Object getProxy(ClassLoader classLoader) throws Exception {return Proxy.newProxyInstance(classLoader,this.advised.getTargetClass().getInterfaces(),this);}/** 处理的增强方法,在这里我们用来重写AOP* @param o* @param method* @param objects* @return* @throws Throwable*/@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,this.advised.getTargetClass());ReflectiveMethodInvocation methodInvocation = new ReflectiveMethodInvocation(this.getProxy(),this.advised.getTarget(),method,objects,this.advised.getTargetClass(),chain);// 执行链开始return methodInvocation.procced();}
}
package spring.framework.aop;
import lombok.Data;
import spring.framework.aop.interceptor.JoinPoint;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.*;
import java.util.List;/*** 这里封装了拦截器*/
@Data
public class ReflectiveMethodInvocation implements JoinPoint {public ReflectiveMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {this.proxy = proxy;this.target = target;this.method = method;this.arguments = arguments;this.targetClass = targetClass;this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;}/*** 要代理对象*/private Object proxy;/*** 要代理的对象*/private Object target;/*** 要代理方法*/private Method method;/*** 要代理方法的参数*/private Object[] arguments;/*** 要代理的目标类*/private Class<?> targetClass;/*** 相当于Advice*/private List<Object> interceptorsAndDynamicMethodMatchers;/*** 当前拦截器的下标*/private int currentInterceptorIndex = -1;/** 执行调用链方法* 1. 这里是使用了职责链模式,因为这里的interceptorsAndDynamicMethodMatchers* 是一个List,存了很多Advice,这里我们称为拦截器,如果扫描到有拦截器就执行它的invoke方法,如果没有就执行它的本来的方法** @return*/@Overridepublic Object proceed() throws Throwable {// 这里要保证要被执行的方法被执行,即使找不到增强方法,也要执行它自己(重点)if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() -1) {this.method.invoke(this.targetClass,this.arguments);}// 这里会拿到要增强的Advice,Advice这里用到了职责链模式,Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof MethodInterceptor) {// 这里要向下转型,转成MethodInterceptor,方便重新调用拦截器的invoke方法return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}else {// 递归保证要有返回return proceed();}}@Overridepublic Object getThis() {return this.target;}
}
前面只是解决了将增强方法和原有方法集成在一起的问题,接下就是完成什么时候执行增强方法,什么时候执行原有方法的细分问题。
首先看看什么时候执行增强方法,因为是所有拦截器公有的方法,所以可以放在抽象拦截器中。
package spring.framework.aop.adapt;import spring.framework.aop.advice.Advice;
import spring.framework.aop.interceptor.JoinPoint;import java.lang.reflect.Method;/*** 抽象拦截器*/
public class AbstractAspectAdvice implements Advice {/*** 要增强的方法(切面类)*/private Method aspectMethod;/*** 要增强的对象(切面类)*/private Object aspectTarget;public AbstractAspectAdvice(Method aspectMethod, Object aspectTarget) {this.aspectMethod = aspectMethod;this.aspectTarget = aspectTarget;}/** 完成增强方法的执行* @param returnValue 返回参数* @param joinPoint 入参* @param throwable 抛出异常*/public void invokeAdviceMethod(Object returnValue, JoinPoint joinPoint,Throwable throwable) throws Throwable {// 没有增强方法,直接返回if (this.aspectMethod == null) {return ;}Class[] parameterTypes = this.aspectMethod.getParameterTypes();// 如果没有参数,执行无参增强方法if (parameterTypes == null || parameterTypes.length == 0) {this.aspectMethod.invoke(this.aspectTarget);}else {Object[] args = new Object[parameterTypes.length];for (int i = 0 ;i < args.length;i++) {if (parameterTypes[i] == JoinPoint.class) {args[i] = joinPoint;}else if (parameterTypes[i] == Throwable.class) {args[i] = throwable;}else if (parameterTypes[i] == Object.class){args[i] = returnValue;}}this.aspectMethod.invoke(this.aspectTarget,args);}}
}
接下来就是不同位置的组合了
前置
package spring.framework.aop.adapt;import spring.framework.aop.ReflectiveMethodInvocation;
import spring.framework.aop.advice.Advice;
import spring.framework.aop.interceptor.JoinPoint;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.Method;/*** 前置拦截器*/
public class MethodBeforeAdviceInterceptor extends AbstractAspectAdvice implements MethodInterceptor {private JoinPoint joinPoint;public MethodBeforeAdviceInterceptor(Method aspectMethod, Object aspectTarget) {super(aspectMethod, aspectTarget);}/** 前置通知,先before执行增强方法 再调用执行链查找是否有其他拦截器* @param methodInvocation* @return* @throws Exception*/@Overridepublic Object invoke(ReflectiveMethodInvocation methodInvocation) throws Throwable {this.joinPoint = methodInvocation;before(methodInvocation.getMethod(),methodInvocation.getArguments(),methodInvocation.getThis());return methodInvocation.proceed();}private void before(Method method,Object args,Object target) throws Throwable {super.invokeAdviceMethod(this.joinPoint,null,null);}
}
2.异常
package spring.framework.aop.adapt;import lombok.Data;
import spring.framework.aop.ReflectiveMethodInvocation;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.Method;/*** 异常拦截器*/
public class AspectJAfterThrowingAdvice extends AbstractAspectAdvice implements MethodInterceptor {/*** 异常名称*/private String throwName;public AspectJAfterThrowingAdvice(Method aspectMethod, Object aspectTarget) {super(aspectMethod, aspectTarget);}public String getThrowName() {return throwName;}public void setThrowName(String throwName) {this.throwName = throwName;}@Overridepublic Object invoke(ReflectiveMethodInvocation methodInvocation) throws Throwable {try {return methodInvocation.proceed();} catch (Throwable throwable) {super.invokeAdviceMethod(methodInvocation,null,throwable);throwable.printStackTrace();throw throwable;}}
}
3.后置(这里跟返回通知不一样,这里不管原有方法会不会抛出异常都会执行)
package spring.framework.aop.adapt;import spring.framework.aop.ReflectiveMethodInvocation;
import spring.framework.aop.interceptor.JoinPoint;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.Method;/*** 后置拦截器*/
public class AspectAfterAdvice extends AbstractAspectAdvice implements MethodInterceptor {private JoinPoint joinPoint;public AspectAfterAdvice(Method method, Object o) {super(method,o);}/** 返回通知,这里会将原有方法的返回值传给一个Object,在增强方法里面可以参数用Object拿到* @param methodInvocation* @return* @throws Throwable*/@Overridepublic Object invoke(ReflectiveMethodInvocation methodInvocation) throws Throwable {Object result = null;try {result = methodInvocation.proceed();return result;} finally {this.joinPoint = methodInvocation;after(result);}}public void after(Object returnValue) throws Throwable {super.invokeAdviceMethod(returnValue,this.joinPoint,null);}
}
4.返回通知,这里只要正常返回都会执行
package spring.framework.aop.adapt;import spring.framework.aop.ReflectiveMethodInvocation;
import spring.framework.aop.interceptor.JoinPoint;
import spring.framework.aop.interceptor.MethodInterceptor;import java.lang.reflect.Method;/*** 返回通知拦截器(具体拦截器)*/
public class AfterReturningAdviceInterceptor extends AbstractAspectAdvice implements MethodInterceptor {/*** 封装参数*/private JoinPoint joinPoint;public AfterReturningAdviceInterceptor(Method method, Object o) {super(method,o);}/** 处理罗跟后置通知差不多,只是不需要finally* @param methodInvocation* @return* @throws Throwable*/@Overridepublic Object invoke(ReflectiveMethodInvocation methodInvocation) throws Throwable {Object result = methodInvocation.proceed();this.joinPoint = methodInvocation;this.afterReturning(result);return result;}public void afterReturning(Object returnValue) throws Throwable {super.invokeAdviceMethod(returnValue,this.joinPoint,null);}
}
到这里,JDK动态代理实现AOP完成了,以后再更新Cligb的没有实现层的动态代理
依赖注入(populateBean)
这里比较简单,之前放了factoryBeanInstanceCache的缓存,所以很多bean都可以从缓存拿,如果没有就递归instantiateBean方法入二级缓存,等下次再装载依赖注入的service时就直接从二级缓存拿了 `
/** DI(依赖注入)* @param beanName* @param beanWrapper* @param beanDefinition*/private void populateBean(String beanName,BeanDefinition beanDefinition,BeanWrapper beanWrapper) {try {Object instance = beanWrapper.getWrappedInstance();Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());// 依赖注入只能是controller层和service层if (!(clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(Service.class))) {return;}// 拿到当前类下声明的所有字段Field[] declaredFields = clazz.getDeclaredFields();for (Field field : declaredFields) {// 只要有Autowired或者Resouce就是依赖注入if (field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(Resource.class)) {Autowired autowired = field.getAnnotation(Autowired.class);Resource resource = field.getAnnotation(Resource.class);// 分别执行不同注解注入的实例if (resource != null) {doPopulateBeanByName(instance,field,resource);}else if (autowired != null) {doPopulateBeanByType(instance,field,autowired);}}}}catch (Exception ex){log.info("依赖注入异常");}}private void doPopulateBeanByType(Object instance, Field field,Autowired autowired) {// @Autowired默认是trueboolean required = autowired.required();if (required) {initFiled(field.getType().getName(),instance,field);}}/** 根据resource注入* @param instance* @param field* @param resource*/private void doPopulateBeanByName(Object instance, Field field, Resource resource) {String resourceBeanName = resource.name().trim();// 如果@Resource没有value值,就直接拿字段类型的全类名if (StringUtils.isEmpty(resourceBeanName)) {resourceBeanName = field.getType().getName();}initFiled(resourceBeanName,instance,field);// 强制字段私有属性field.setAccessible(true);}/** 根据全类名注入* @param filedName* @param instance* @param field*/private void initFiled(String filedName,Object instance,Field field) {try {field.setAccessible(true);if (this.factoryBeanInstanceCache.get(filedName) != null) {field.set(instance,this.factoryBeanInstanceCache.get(filedName).getWrappedClass());}else {field.set(instance,this.instantiateBean(null,super.beanDefinitionMap.get(filedName)));}}catch (Exception ex){log.error("根据全类名注入属性异常");log.error(ex.toString());}}
MVC
mvc的目的就是根据请求参数,找到Handler处理方法,将处理结果返回给用户,
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找 Handler,可以根据xml配置、注解进行查找
第三步:处理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView,ModelAndView是springmvc框架的一个底层对象,包括 Model和view
第八步:前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(jsp)
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到response域
第十一步:前端控制器向用户响应结果
MVC九大控件
初始化这九大组件是在前端控制器的init的方法执行的
@Overridepublic void init() {if (this.applicationClass.isAnnotationPresent(SpringBootApplication.class)){this.applicationContext = new ApplicationContext(this.applicationClass);// 初始化MVCinitStrategies(this.applicationContext);log.error("容器初始化完成了。。。。。。");}}/** 初始化MVC九大部件* @param applicationContext*/private void initStrategies(ApplicationContext applicationContext) {initMultipartResolver(applicationContext);initLocaleResolver(applicationContext);initThemeResolver(applicationContext);initHandlerMappings(applicationContext);initHandlerAdapters(applicationContext);initHandlerExceptionResolvers(applicationContext);initRequestToViewNameTranslator(applicationContext);initViewResolvers(applicationContext);initFlashMapManager(applicationContext);}/** 9.参数缓存器* @param applicationContext*/private void initFlashMapManager(ApplicationContext applicationContext) {}/** 8. 视图转换器,模板引擎* @param applicationContext*/private void initViewResolvers(ApplicationContext applicationContext) {String template = propertiesConfig.properties.getProperty("templets");if (template != null) {template = this.getClass().getClassLoader().getResource(template).getFile();}else {template = this.getClass().getClassLoader().getResource("templates").getFile();}File fileDir = new File(template);for (File templateRootDir : fileDir.listFiles()){//为了一个页面兼容多个模板this.viewResovlers.add(new ViewResovler(template));}}/** 7.视图提取器,从request中获取ViewName* @param applicationContext*/private void initRequestToViewNameTranslator(ApplicationContext applicationContext) {}/** 6. 异常拦截器* @param applicationContext*/private void initHandlerExceptionResolvers(ApplicationContext applicationContext) {}/** 5.处理器适配器(解决动态参数)* @param applicationContext*/private void initHandlerAdapters(ApplicationContext applicationContext) {for (HandlerMapping mapping : this.handlerMappings) {this.handlerAdapters.add(new RequestMappingHandlerAdapter());}}/** 4.保存Url与方法的映射(处理器映射器)* @param applicationContext*/private void initHandlerMappings(ApplicationContext applicationContext) {String[] beanDenfintionNames = applicationContext.getBeanDefinitionNames();// 这里遍历beanDenfintionNames 从IOC容器拿Bean// 拿到Controller注解的类for (String name : beanDenfintionNames) {Object controller = applicationContext.getBean(name);Class<?> clazz = controller.getClass();// 处理根路径if (clazz.isAnnotationPresent(Controller.class)) {// 如果有RequestMapping的话String baseUrl = "";if (clazz.isAnnotationPresent(RequestMapping.class)) {baseUrl = clazz.getAnnotation(RequestMapping.class).value();}// 拿到所有方法下有RequestMapping注解的for (Method method : clazz.getDeclaredMethods()) {if (! method.isAnnotationPresent(RequestMapping.class)) {continue;}RequestMapping mapping = method.getAnnotation(RequestMapping.class);// 这里用到了正则,先根路径跟方法路径拼接,然后// 转/String regx = ("/" + baseUrl + mapping.value().replaceAll("\\.",".*")).replaceAll("/*","/");// 编译正则Pattern pattern = Pattern.compile(regx);this.handlerMappings.add(new HandlerMapping(controller,method,pattern));}}}}/** 3.主题模板处理器* @param applicationContext*/private void initThemeResolver(ApplicationContext applicationContext) {}/** 2.本地语言环境* @param applicationContext*/private void initLocaleResolver(ApplicationContext applicationContext) {}/** 1.多文件上传* @param applicationContext*/private void initMultipartResolver(ApplicationContext applicationContext) {}
初始化完组件,下面就是请求分发的,前端控制器的作用就是请求分发,doPost和doGet请求对应get和post请求
/** 请求分发* @param req* @param resp*/private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception{// 1. 从请求的URL拿到HandleMapperingHandlerMapping mapping = getHandler(req,resp);// 2. 如果没找到映射器,返回404if (mapping == null) {//404ModelAndView modelAndView = new ModelAndView("404");processDispatchResult(req,resp,modelAndView);return;}// 3.根据HandlerMapping(handler) 找到HandlerAdapterHandlerAdapter adapter = getHandlerAdapter(mapping);// 4.执行handler,拿到ModelAndViewModelAndView modelAndView = adapter.handler(req, resp, mapping);// 5.返回数据processDispatchResult(req,resp,modelAndView);}
/** 从请求的URL拿到HandleMappering* @param req* @param response* @return*/private HandlerMapping getHandler(HttpServletRequest req,HttpServletResponse response) {if (this.handlerMappings.isEmpty()) {return null;}String requestURI = req.getRequestURI();String contextPath = req.getContextPath();String url = requestURI.replace(contextPath,"").replace("/+","/");for (HandlerMapping mapping : this.handlerMappings) {// 匹配到了映射的Mappingif (mapping.getPattern().matcher(url).matches()) {return mapping;}}return null;}
/** 根据HandlerMapping(handler) 找到HandlerAdapter* @param handlerMapping* @return*/private HandlerAdapter getHandlerAdapter(HandlerMapping handlerMapping) {HandlerAdapter adapter = this.handlerAdapters.get(handlerMapping);if (adapter.supports(handlerMapping)) {return adapter;}return null;}
/**这里会调用Handler里边的method方法,拿到ModelAndView* @param request* @param response* @param handler* @return* @throws InvocationTargetException* @throws IllegalAccessException*/@Overrideprotected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMapping handler) throws InvocationTargetException, IllegalAccessException {// 为了保证调用method方法参数的一致性,需要一个参数与顺序对应的mapMap<String,Integer> paramsIndexMapping = new HashMap<String, Integer>(16);/* 1. 先拿到原有方法的参数,按出现的顺序方法paramsIndexMapping这里是先拿到参数有@RequestMapping标志的*/Annotation[][] annotations = handler.getMethod().getParameterAnnotations();for (int i = 0; i< annotations.length;i++) {for (Annotation an : annotations[i]) {if (an instanceof RequestParam) {String paramName = ((RequestParam) an).value();if (!"".equals(paramName.trim())) {paramsIndexMapping.put(paramName,i);}}}}// 2.再将没有RequestMapping注解的参数放入paramsIndexMappingClass<?>[] classes = handler.getMethod().getParameterTypes();for (int i = 0;i<classes.length;i++) {Class<?> parameterType = classes[i];if (parameterType == HttpServletRequest.class || parameterType == HttpServletResponse.class) {paramsIndexMapping.put(parameterType.getName(),i);}}// 3.处理原有方法的参数与请求参数的映射Map<String,String[]> paramsMap = request.getParameterMap();// 保存实际的参数集合Object[] args = new Object[classes.length];if (POST.equals(request.getMethod())) {Map<String,Object> postParamsMap = RequestUtils.getParamByStream(request);for (Map.Entry<String,Object> param : postParamsMap.entrySet()) {if (!paramsIndexMapping.containsKey(param.getKey())) {continue;}Integer index = paramsIndexMapping.get(param.getKey());args[index] = param.getValue();}}else if (GET.equals(request.getMethod())){for (Map.Entry<String,String[]> param : paramsMap.entrySet()) {// 这里会是这种形式[value],使用正则把[]去掉String value = Arrays.toString(paramsMap.get(param.getKey())).replaceAll("\\[|\\]","").replaceAll("\\s","");if (!paramsIndexMapping.containsKey(param.getKey())) {continue;}Integer index = paramsIndexMapping.get(param.getKey());args[index] = caseTypeArgs(value,classes[index]);}}if(paramsIndexMapping.containsKey(HttpServletRequest.class.getName())){Integer index = paramsIndexMapping.get(HttpServletRequest.class.getName());args[index] = request;}if(paramsIndexMapping.containsKey(HttpServletResponse.class.getName())){Integer index = paramsIndexMapping.get(HttpServletResponse.class.getName());args[index] = response;}// 4.拿到实际参数去调用handler的method方法Object result = handler.getMethod().invoke(handler.getController(),args);// 5. 处理返回值为void 或者为null的情况if (result == null || result instanceof Void) {return null;}// 6.处理modelAndView的情况,如果是就返回,不是就封装成ModelAndViewboolean isMv = handler.getMethod().getReturnType() == ModelAndView.class;if (isMv) {return (ModelAndView) result;}//// 取其Model 直接读出来try {if (handler.getMethod().getAnnotation(ResponseBody.class) != null) {response.setCharacterEncoding("utf-8");response.setContentType("application/json; charset=utf-8");response.getWriter().write(JSON.toJSONString(result));}} catch (IOException e) {e.printStackTrace();}return null;}
/** 通过ViewResolver解析ModelAndView,得到View对象或者json字符串* @param req* @param resp* @param modelAndView*/public static void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, ModelAndView modelAndView) throws IOException {if (modelAndView == null) {return;}if (viewResovlers.isEmpty()) {return;}// 这里感觉用一个viewResovler就可以解决,但是用了list的,可以优化for (ViewResovler viewResovler : viewResovlers) {//解析页面View view = viewResovler.resolveViewName(req,resp,modelAndView.getViewName());//把数据响应到浏览器view.reader(req,resp,modelAndView.getModel());//这里不return的话,有几个页面,会把同一个页面的内容输出几次return;}}