为了简化XML解析, 用application.properties 来代替application.xml,具体配置如下:
#scan config
scanPackage=com.hezhiqin.demo
templateRoot=layouts
#多切面配置可以在key前面加前缀
#例如 aspect.logAspect.
#切面表达式,expression#
pointCut=public .* com.hezhiqin.demo.service..*Service..*(.*)
#切面类#
aspectClass=com.hezhiqin.demo.aspect.LogAspect
#切面前置通知#
aspectBefore=before
#切面后置通知#
aspectAfter=after
#切面异常通知#
aspectAfterThrow=afterThrowing
#切面异常类型#
aspectAfterThrowingName=java.lang.Exception
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>HomeWork</artifactId>
<groupId>hezhiqin.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Spring2.1</artifactId>
<packaging>war</packaging>
<name>Spring2.1 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
<build>
<finalName>Spring2.1</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<display-name>HZQmvc</display-name>
<servlet>
<servlet-name>hzqmvc</servlet-name>
<servlet-class>com.hezhiqin.formework.webmvc.servlet.HZQDispathcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hzqmvc</servlet-name>
<url-pattern>/*
annotation(自定义配置)模块
Annotation 的代码实现我们还是沿用mini 版本的不变,复制过来便可。
HZQAutowired
package com.hezhiqin.formework.annotation;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HZQAutowired {
String value() default "";
}
HZQController
package com.hezhiqin.formework.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HZQController {
String value() default "";
}
HZQRequestMapping
package com.hezhiqin.formework.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HZQRequestMapping {
String value() default "";
}
HZQRequestParam
package com.hezhiqin.formework.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HZQRequestParam {
String value() default "";
}
HZQService
package com.hezhiqin.formework.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HZQService {
String value() default "";
}
HZQBeanFactory
package com.hezhiqin.formework.beans;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-10-27 13:01
*/
public interface HZQBeanFactory {
/**
*@Description:
*@Param:
*@return:
*@Author: hezhiqin
*@date: 2019/10/27
*/
Object getBean(String beanName) throws Exception;
}
package com.hezhiqin.formework.beans.config;
import lombok.Data;
/**
* @program: homeWork
* @description:用来存储配置文件中的信息,相当于保存在内存中的配置
* @author: hezhiqin
* @create: 2019-10-27 13:28
*/
@Data
public class HZQBeanDefinition {
private String beanClassName;
//是否延时加载
private boolean lazyInit = false;
private String factoryBeanName;
//是否单例
private boolean isSingleton = true;
}
GPBeanWrapper
package com.hezhiqin.formework.beans;
/**
* @program: homeWork
* @description: 存储Bean所有的信息(代理,依赖关系等)
* @author: hezhiqin
* @create: 2019-10-28 13:59
*/
public class HZQBeanWrapper {
private Object wrappedInstance;
private Class<?> wrappedClass;
public HZQBeanWrapper(Object wrappedInstance) {
this.wrappedInstance = wrappedInstance;
wrappedClass = wrappedInstance.getClass();
}
public Object getWrappedInstance() {
return wrappedInstance;
}
// 返回代理以后的Class
// 可能会是这个$Proxy0
public Class<?> getWrappedClass() {
return wrappedClass;
}
}
HZQAbstractApplicationContext
package com.hezhiqin.formework.context.support;
/**
* @program: homeWork
* @description: 单例工厂的顶层设计
* @author: hezhiqin
* @create: 2019-10-27 13:10
*/
public abstract class HZQAbstractApplicationContext {
//受保护的,只提供给子类去重写
protected void refresh() throws ClassNotFoundException {
}
}
HZQAbstractApplicationContext
package com.hezhiqin.formework.beans.support;
import com.hezhiqin.formework.beans.config.HZQBeanDefinition;
import com.hezhiqin.formework.context.support.HZQAbstractApplicationContext;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @program: homeWork
* @description:存储注册信息的BeanDefinition
* @author: hezhiqin
* @create: 2019-10-27 13:16
*/
public class HZQDefaultListableBeanFactory extends HZQAbstractApplicationContext {
/** Map of bean definition objects, keyed by bean name. */
protected final Map<String, HZQBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, HZQBeanDefinition>(256);
}
HZQApplicationcontext
先来看一下HZQApplicationcontext的类图,会清晰一点
package com.hezhiqin.formework.context;
import com.hezhiqin.formework.annotation.HZQAutowired;
import com.hezhiqin.formework.annotation.HZQController;
import com.hezhiqin.formework.annotation.HZQService;
import com.hezhiqin.formework.aop.HZQAopProxy;
import com.hezhiqin.formework.aop.HZQCglibAopProxy;
import com.hezhiqin.formework.aop.HZQJdkDynamicAopProxy;
import com.hezhiqin.formework.aop.config.HZQAopConfig;
import com.hezhiqin.formework.aop.support.HZQAdvisedSupport;
import com.hezhiqin.formework.beans.HZQBeanFactory;
import com.hezhiqin.formework.beans.HZQBeanWrapper;
import com.hezhiqin.formework.beans.config.HZQBeanDefinition;
import com.hezhiqin.formework.beans.config.HZQBeanPostProcessor;
import com.hezhiqin.formework.beans.support.HZQBeanDefinitionReader;
import com.hezhiqin.formework.beans.support.HZQDefaultListableBeanFactory;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @program: homeWork
* @description:顶级容器实现类
* @author: hezhiqin
* @create: 2019-10-27 13:07
*/
public class HZQApplicationcontext extends HZQDefaultListableBeanFactory implements HZQBeanFactory {
private String[] configLocations;
//单例的的IOC容器
private Map<String,Object> singletonObject= new ConcurrentHashMap<String,Object>();
//通用的IOC容器
private Map<String,HZQBeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<String,HZQBeanWrapper>();
HZQBeanDefinitionReader hzqBeanDefinitionReader;
public HZQApplicationcontext(String... configLocations) {
this.configLocations =configLocations;
try {
refresh();
} catch (Exception e) {
e.printStackTrace();
}
}
public String[] getBeanDefinitionNames(){
Set<String> set = beanDefinitionMap.keySet();
return set.toArray(new String[this.beanDefinitionMap.size()]);
}
int getBeanDefinitionCount(){
return beanDefinitionMap.size();
}
//初始化
@Override
protected void refresh() throws ClassNotFoundException {
//1.ioc第一步,定位配置文件
hzqBeanDefinitionReader = new HZQBeanDefinitionReader(configLocations);
//2.加载配置文件,扫描相关的类,封装成BeanDefinition
List<HZQBeanDefinition> hzqBeanDefinitions = hzqBeanDefinitionReader.loadBeanDefinitions();
//3.注册,配置信息放入容器中(伪IOC容器,只保存了配置信息,真正的IOC在beanWapper)
doRegisterBeanDefinition(hzqBeanDefinitions);
//4.把不是延时加载的类,提前的初始化
doAutoWrited();
}
private void doRegisterBeanDefinition(List<HZQBeanDefinition> hzqBeanDefinitions) {
for (HZQBeanDefinition hzqBeanDefinition: hzqBeanDefinitions) {
super.beanDefinitionMap.put(hzqBeanDefinition.getFactoryBeanName(),hzqBeanDefinition);
}
}
private void doAutoWrited() {
for (Map.Entry<String,HZQBeanDefinition> beanDefinitionEntry: super.beanDefinitionMap.entrySet()) {
String beanName = beanDefinitionEntry.getKey();
if (!beanDefinitionEntry.getValue().isLazyInit()){
try {
getBean(beanName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
public Object getBean(String beanName) throws Exception {
HZQBeanPostProcessor hzqBeanPostProcessor = new HZQBeanPostProcessor();
//1.初始化
Object instantiateBean = instantiateBean(beanName,this.beanDefinitionMap.get(beanName));
//对象封装到BeanWrapper中
HZQBeanWrapper hzqBeanWrapper = new HZQBeanWrapper(instantiateBean);
hzqBeanPostProcessor.postProcessBeforeInitialization(instantiateBean,beanName);
//2.将BeanWrapper 保存的IOC 容器中
if (!factoryBeanInstanceCache.containsKey(beanName)){
factoryBeanInstanceCache.put(beanName,hzqBeanWrapper);
}
hzqBeanPostProcessor.postProcessAfterInitialization(instantiateBean,beanName);
//3.注入
populateBean(beanName,this.beanDefinitionMap.get(beanName),hzqBeanWrapper);
return factoryBeanInstanceCache.get(beanName).getWrappedInstance();
}
//注入
private void populateBean(String beanName, HZQBeanDefinition hzqBeanDefinition, HZQBeanWrapper hzqBeanWrapper) {
//1、拿到实例
Object object = hzqBeanWrapper.getWrappedInstance();
//2.判断只有加了注解的类,才执行注入
Class aClass = hzqBeanWrapper.getWrappedClass();
//如果不是
if (!(aClass.isAnnotationPresent(HZQController.class)||aClass.isAnnotationPresent(HZQService.class))){
return;
}
Field[] fields = aClass.getDeclaredFields();
for (Field field: fields) {
if (!field.isAnnotationPresent(HZQAutowired.class)){continue;}
//判断这个字段有没有Auto
HZQAutowired hzqAutowired = field.getAnnotation(HZQAutowired.class);
String autowiredBeanName = hzqAutowired.value().trim();
if ("".equals(autowiredBeanName)){
autowiredBeanName = field.getType().getSimpleName();
}
field.setAccessible(true);
try {
//为什么会为null?因为循环顺序的问题
if (this.factoryBeanInstanceCache.get(autowiredBeanName)==null){
try {
field.set(object,Class.forName(this.beanDefinitionMap.get(autowiredBeanName).getBeanClassName()).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}else {
field.set(object,this.factoryBeanInstanceCache.get(autowiredBeanName).getWrappedInstance());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
private Object instantiateBean(String beanName, HZQBeanDefinition hzqBeanDefinition) {
//1.拿到要实例化的对象的类名
String className = hzqBeanDefinition.getBeanClassName();
//2.反射实例化,得到对象
Object instance = null;
try {
//假设默认单例
if (singletonObject.containsKey(className)){
instance = this.singletonObject.get(className);
}else {
Class<?> aClass = Class.forName(className);
instance = aClass.newInstance();
HZQAdvisedSupport config = instantionAopConfig(hzqBeanDefinition);
config.setTargetClass(aClass);
config.setTarget(instance);
//符合PointCut的规则的话,创建代理对象
if(config.pointCutMatch()) {
instance = createProxy(config).getProxy();
}
this.singletonObject.put(className,instance);
this.singletonObject.put(hzqBeanDefinition.getFactoryBeanName(),instance);
}
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
private HZQAopProxy createProxy(HZQAdvisedSupport config) {
Class targetClass = config.getTargetClass();
if (targetClass.getInterfaces().length>0){
return new HZQJdkDynamicAopProxy(config);
}
return new HZQCglibAopProxy(config);
}
private HZQAdvisedSupport instantionAopConfig(HZQBeanDefinition hzqBeanDefinition) {
HZQAopConfig hzqAopConfig = new HZQAopConfig();
hzqAopConfig.setPointCut(this.hzqBeanDefinitionReader.getConfigContext().getProperty("pointCut"));
hzqAopConfig.setAspectClass(this.hzqBeanDefinitionReader.getConfigContext().getProperty("aspectClass"));
hzqAopConfig.setAspectBefore(this.hzqBeanDefinitionReader.getConfigContext().getProperty("aspectBefore"));
hzqAopConfig.setAspectAfter(this.hzqBeanDefinitionReader.getConfigContext().getProperty("aspectAfter"));
hzqAopConfig.setAspectAfterThrow(this.hzqBeanDefinitionReader.getConfigContext().getProperty("aspectAfterThrow"));
hzqAopConfig.setAspectAfterThrowingName(this.hzqBeanDefinitionReader.getConfigContext().getProperty("aspectAfterThrowingName"));
return new HZQAdvisedSupport(hzqAopConfig);
}
public Properties getCongif(){
return this.hzqBeanDefinitionReader.getConfigContext();
}
}
HZQApplicationContextAware
package com.hezhiqin.formework.context;
/**
* @program: homeWork
* @description: 通过解耦的方式获取IOC容器的顶层设计
* 后面将通过一个监听器去扫描所以的类,只要实现了此接口
* 将自动调用setApplicationContext,从而将IOC容器注入到目标类中
* @author: hezhiqin
* @create: 2019-10-27 13:38
*/
public interface HZQApplicationContextAware {
void setApplicationContext(HZQApplicationcontext applicationContext) throws Exception;
}
1、寻找入口,阅读Spring的源码可以得知,入口在构造方法中,我们仿造Spring手写
public HZQApplicationcontext(String... configLocations) {
this.configLocations =configLocations;
try {
refresh();
} catch (Exception e) {
e.printStackTrace();
}
}
2、初始化
//初始化
@Override
protected void refresh() throws ClassNotFoundException {
//1.ioc第一步,定位配置文件
hzqBeanDefinitionReader = new HZQBeanDefinitionReader(configLocations);
//2.加载配置文件,扫描相关的类,封装成BeanDefinition
List<HZQBeanDefinition> hzqBeanDefinitions = hzqBeanDefinitionReader.loadBeanDefinitions();
//3.注册,配置信息放入容器中(伪IOC容器,只保存了配置信息,真正的IOC在beanWapper)
doRegisterBeanDefinition(hzqBeanDefinitions);
//4.把不是延时加载的类,提前的初始化
doAutoWrited();
}
通过HZQBeanDefinitionReader。读取配置文件,扫描指定包下的所有相关类
然后加载配置文件,扫描相关的类,封装成BeanDefinition
HZQBeanDefinitionReader
package com.hezhiqin.formework.beans.support;
import com.hezhiqin.formework.beans.config.HZQBeanDefinition;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-10-28 12:40
*/
public class HZQBeanDefinitionReader {
//保存扫描的所有的类名
private List<String> registyBeanClasses = new ArrayList<String>();
//获取配置信息,定位到需要扫描的包下面
Properties configContext = new Properties();
private final String SCAN_PACKGE = "scanPackage";
public HZQBeanDefinitionReader (String... locations){
InputStream is = this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath:",""));
try {
configContext.load(is);
doScanner(configContext.getProperty(SCAN_PACKGE));
} catch (IOException e) {
e.printStackTrace();
}finally {
if (is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//把配置文件中扫描到的所有的配置信息转换为GPBeanDefinition对象,以便于之后IOC操作方便
public List<HZQBeanDefinition> loadBeanDefinitions() throws ClassNotFoundException {
List<HZQBeanDefinition> result = new ArrayList<HZQBeanDefinition>();
for (String registyBeanClass: registyBeanClasses) {
Class<?> beanClass = Class.forName(registyBeanClass);
//如果是一个接口,是不能实例化的
//用它实现类来实例化
if(beanClass.isInterface()) { continue; }
//beanName有三种情况:
//1、默认是类名首字母小写
//2、自定义名字
//3、接口注入
result.add(doCreateBeanDefintion(toLowerFirstCase(beanClass.getSimpleName()),beanClass.getName()));
// result.add(doCreateBeanDefinition(beanClass.getName(),beanClass.getName()));
Class<?> [] interfaces = beanClass.getInterfaces();
for (Class<?> i : interfaces) {
//如果是多个实现类,只能覆盖
//为什么?因为Spring没那么智能,就是这么傻
//这个时候,可以自定义名字
result.add(doCreateBeanDefintion(i.getSimpleName(),beanClass.getName()));
}
}
return result;
}
public Properties getConfigContext() {
return configContext;
}
/**
* @param scanPackage
* 扫描配置的路径,将所有相关的类放入容器中
*/
private void doScanner(String scanPackage) {
//scanPackage = com.hezhiqin ,存储的是包路径
//转换为文件路径,实际上就是把.替换为/就 OK 了
URL url = this.getClass().getClassLoader().getResource("/" +
scanPackage.replaceAll("\\.","/"));//将扫描的包的.换成/
File classDir = new File(url.getFile());
for (File file : classDir.listFiles()) {
if (file.isDirectory()) {//如果是一个文件
doScanner(scanPackage + "." +file.getName());
}else {
if(!file.getName().endsWith(".class")){continue;}//不是一个class文件则跳过
String clazzName = (scanPackage + "." + file.getName().replace(".class",""));//获取classpath
//
registyBeanClasses.add(clazzName);
}
}
}
//吧每一个配置信息解析成为BeanDefintion
private HZQBeanDefinition doCreateBeanDefintion(String factoryBeanName,String beanClassName){
HZQBeanDefinition hzqBeanDefinition = new HZQBeanDefinition();
hzqBeanDefinition.setBeanClassName(beanClassName);
hzqBeanDefinition.setFactoryBeanName(factoryBeanName);
return hzqBeanDefinition;
}
private String toLowerFirstCase(String simpleName) {
char [] chars = simpleName.toCharArray();
//之所以加,是因为大小写字母的 ASCII 码相差 32,
// 而且大写字母的 ASCII 码要小于小写字母的 ASCII 码
//在 Java 中,对 char 做算学运算,实际上就是对 ASCII 码做算学运算
if (isUpperCase(chars[0])) {
chars[0] += 32;
}
return String.valueOf(chars);
}
/*
* 是否是大写
*/
public boolean isUpperCase(char c) {
return c >=65 && c <= 90;
}
}
至此 我们将所有的在配置文件中"scanPackage" 下所有的类都扫描到了IOC容器中
上面介绍的是把指定的类保存在IOC容器中,在之前的源码分析中,我们已经了解到,依赖注入的入口是从getBean()方法开始的,前
面的IOC 手写部分基本流程已通。先在HZQApplicationContext 中定义好IOC 容器,一个是HZQBeanWrapper,一个是单例对象缓存
public class HZQApplicationcontext extends HZQDefaultListableBeanFactory implements HZQBeanFactory {
private String[] configLocations;
//单例的的IOC容器
private Map<String,Object> singletonObject= new ConcurrentHashMap<String,Object>();
//通用的IOC容器
private Map<String,HZQBeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<String,HZQBeanWrapper>();
}
上一步注入的方法是doAutoWrited(),我们往里走。。。。。。。
private void doAutoWrited() {
for (Map.Entry<String,HZQBeanDefinition> beanDefinitionEntry: super.beanDefinitionMap.entrySet()) {
String beanName = beanDefinitionEntry.getKey();
if (!beanDefinitionEntry.getValue().isLazyInit()){
try {
getBean(beanName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
下面,我们从完善getBean()方法开始:
@Override
public Object getBean(String beanName) throws Exception {
HZQBeanPostProcessor hzqBeanPostProcessor = new HZQBeanPostProcessor();
//1.初始化
Object instantiateBean = instantiateBean(beanName,this.beanDefinitionMap.get(beanName));
//对象封装到BeanWrapper中
HZQBeanWrapper hzqBeanWrapper = new HZQBeanWrapper(instantiateBean);
hzqBeanPostProcessor.postProcessBeforeInitialization(instantiateBean,beanName);
//2.将BeanWrapper 保存的IOC 容器中
if (!factoryBeanInstanceCache.containsKey(beanName)){
factoryBeanInstanceCache.put(beanName,hzqBeanWrapper);
}
hzqBeanPostProcessor.postProcessAfterInitialization(instantiateBean,beanName);
//3.注入
populateBean(beanName,this.beanDefinitionMap.get(beanName),hzqBeanWrapper);
return factoryBeanInstanceCache.get(beanName).getWrappedInstance();
}
private Object instantiateBean(String beanName, HZQBeanDefinition hzqBeanDefinition) {
//1.拿到要实例化的对象的类名
String className = hzqBeanDefinition.getBeanClassName();
//2.反射实例化,得到对象
Object instance = null;
try {
//假设默认单例
if (singletonObject.containsKey(className)){
instance = this.singletonObject.get(className);
}else {
Class<?> aClass = Class.forName(className);
instance = aClass.newInstance();
HZQAdvisedSupport config = instantionAopConfig(hzqBeanDefinition);
config.setTargetClass(aClass);
config.setTarget(instance);
//符合PointCut的规则的话,创建代理对象
if(config.pointCutMatch()) {
instance = createProxy(config).getProxy();
}
this.singletonObject.put(className,instance);
this.singletonObject.put(hzqBeanDefinition.getFactoryBeanName(),instance);
}
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
//注入
private void populateBean(String beanName, HZQBeanDefinition hzqBeanDefinition, HZQBeanWrapper hzqBeanWrapper) {
//1、拿到实例
Object object = hzqBeanWrapper.getWrappedInstance();
//2.判断只有加了注解的类,才执行注入
Class aClass = hzqBeanWrapper.getWrappedClass();
//如果不是
if (!(aClass.isAnnotationPresent(HZQController.class)||aClass.isAnnotationPresent(HZQService.class))){
return;
}
Field[] fields = aClass.getDeclaredFields();
for (Field field: fields) {
if (!field.isAnnotationPresent(HZQAutowired.class)){continue;}
//判断这个字段有没有Auto
HZQAutowired hzqAutowired = field.getAnnotation(HZQAutowired.class);
String autowiredBeanName = hzqAutowired.value().trim();
if ("".equals(autowiredBeanName)){
autowiredBeanName = field.getType().getSimpleName();
}
field.setAccessible(true);
try {
//为什么会为null?因为循环顺序的问题
if (this.factoryBeanInstanceCache.get(autowiredBeanName)==null){
try {
field.set(object,Class.forName(this.beanDefinitionMap.get(autowiredBeanName).getBeanClassName()).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}else {
field.set(object,this.factoryBeanInstanceCache.get(autowiredBeanName).getWrappedInstance());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
HZQBeanWrapper
package com.hezhiqin.formework.beans;
/**
* @program: homeWork
* @description: 存储Bean实例的信息
* @author: hezhiqin
* @create: 2019-10-28 13:59
*/
public class HZQBeanWrapper {
private Object wrappedInstance;
private Class<?> wrappedClass;
public HZQBeanWrapper(Object wrappedInstance) {
this.wrappedInstance = wrappedInstance;
wrappedClass = wrappedInstance.getClass();
}
public Object getWrappedInstance() {
return wrappedInstance;
}
// 返回代理以后的Class
// 可能会是这个$Proxy0
public Class<?> getWrappedClass() {
return wrappedClass;
}
}
HZQBeanPostProcessor
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-10-31 13:49
*/
public class HZQBeanPostProcessor {
//为在Bean 的初始化前提供回调入口
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
//为在Bean 的初始化之后提供回调入口
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
return bean;
}
}
至此,DI 部分就完成了。
在此总结一下执行顺序:
1.refresh方法中的doAutoWrited是DI的起始点
2.在doAutoWrited方法中调用了getBean方法
3.调用以下方法进行初始化和赋值(注入)
HZQDispatcherServlet
1.init方法中 初始化application容器,初始化九大组件
2.initHandlerMappings中将url和类,方法的关系保存起来
3.initHandlerAdapters 初始化参数适配器
package com.hezhiqin.formework.webmvc.servlet;
import com.hezhiqin.formework.annotation.HZQController;
import com.hezhiqin.formework.annotation.HZQRequestMapping;
import com.hezhiqin.formework.context.HZQApplicationcontext;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Administrator
*所有的核心逻辑卸载init方法中
*/
@Slf4j
public class HZQDispathcherServlet extends HttpServlet {
private final String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";
private HZQApplicationcontext hzqApplicationcontext;
private List<HZQHandlerMapping> handlerMappings = new ArrayList<HZQHandlerMapping>();
private Map<HZQHandlerMapping, HZQHandlerAdapter> handlerAdapters = new HashMap<HZQHandlerMapping,HZQHandlerAdapter>();
private List<HZQViewResolver> viewResolvers = new ArrayList<HZQViewResolver>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
this.doDispather(req, resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500 Exception,Details: " + Arrays.toString(e.getStackTrace()));
}
}
@Override
public void init(ServletConfig config) throws ServletException {
//1.初始化application
hzqApplicationcontext = new HZQApplicationcontext(config.getInitParameter(CONTEXT_CONFIG_LOCATION));
//2.初始化九大组件
this.initStrategies(hzqApplicationcontext);
}
private void doDispather(HttpServletRequest req, HttpServletResponse resp)throws Exception {
//1.通过重request中拿到url,去匹配一个handlerMapping
HZQHandlerMapping handlerMapping = getHandler(req);
if (handlerMapping==null){
processDispatchResult(req,resp,new HZQModelAndView("404"));
return;
}
//2. 准备调用钱参数
HZQHandlerAdapter hzqHandlerAdapter = getHandlerAdapter(handlerMapping);
//3.真正的调用方法,返回的HZQModelAndView 包含了页面上的值,和页面模板名称
HZQModelAndView hzqModelAndView = hzqHandlerAdapter.handle(req,resp,handlerMapping);
//4.真正的输出
processDispatchResult(req,resp,hzqModelAndView);
}
//把给我的ModelAndView转变成HTML或者Json、freemark
private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, HZQModelAndView hzqModelAndView)throws Exception{
if (null==hzqModelAndView){
return;
}
//如果hzqModelAndView不为空,则将hzqModelAndView进行渲染
if(this.viewResolvers.isEmpty()){
return;
}else {
for (HZQViewResolver hzqViewResolver :viewResolvers) {
HZQView view = hzqViewResolver.resolveViewName(hzqModelAndView.getViewName(),null);
view.render(hzqModelAndView.getModel(),req,resp);
return;
}
}
}
private HZQHandlerAdapter getHandlerAdapter(HZQHandlerMapping handlerMapping) {
if (this.handlerAdapters.isEmpty()){
return null;
}
HZQHandlerAdapter hzqHandlerAdapter = this.handlerAdapters.get(handlerMapping);
if (hzqHandlerAdapter.supports(handlerMapping)){
return hzqHandlerAdapter;
}
return null;
}
private HZQHandlerMapping getHandler(HttpServletRequest req) throws Exception {
if(handlerMappings.isEmpty()){ return null; }
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
System.out.println("解析的URL"+url);
for (HZQHandlerMapping handler : handlerMappings) {
Matcher matcher = handler.getPattern().matcher(url);
if(!matcher.matches()){ continue; }
return handler;
}
return null;
}
//初始化策略
protected void initStrategies(HZQApplicationcontext context) {
//多文件上传的组件
initMultipartResolver(context);
//初始化本地语言环境
initLocaleResolver(context);
//初始化模板处理器
initThemeResolver(context);
//handlerMapping
initHandlerMappings(context);
//初始化参数适配器
initHandlerAdapters(context);
//初始化异常拦截器
initHandlerExceptionResolvers(context);
//初始化视图预处理器
initRequestToViewNameTranslator(context);
//初始化视图转换器
initViewResolvers(context);
initFlashMapManager(context);
}
private void initLocaleResolver(HZQApplicationcontext context) {
}
private void initMultipartResolver(HZQApplicationcontext context) {
}
private void initThemeResolver(HZQApplicationcontext context) {
}
private void initHandlerMappings(HZQApplicationcontext context) {
String[] beanNames = context.getBeanDefinitionNames();
try {
for (String beanName : beanNames) {
Object controller = context.getBean(beanName);
Class<?> controllerClass = controller.getClass();
if (!controllerClass.isAnnotationPresent(HZQController.class)){
continue;
}
String url = "";
if(controllerClass.isAnnotationPresent(HZQRequestMapping.class)){
HZQRequestMapping requestMapping = controllerClass.getAnnotation(HZQRequestMapping.class);
url = requestMapping.value();
}
//获取 Method 的 url 配置
Method[] methods = controllerClass.getMethods();
for (Method method : methods) {
//没有加 RequestMapping 注解的直接忽略
if(!method.isAnnotationPresent(HZQRequestMapping.class)){ continue; }
//映射 URL
HZQRequestMapping requestMapping = method.getAnnotation(HZQRequestMapping.class);
String regex = ("/" + url + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+", "/");
Pattern pattern = Pattern.compile(regex);
handlerMappings.add(new HZQHandlerMapping(controller,method,pattern));
log.info("mapping " + regex + "," + method);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
private void initHandlerAdapters(HZQApplicationcontext context) {
//把一个request请求变成一个handler,参数都是字符串的,自动匹配到handler中的形参
//要拿到handlerMapping才能干活
//意味着,有几个handlerMapping,就有几个HandlerAdapters
for (HZQHandlerMapping handlerMapping : this.handlerMappings) {
//HZQHandlerMapping HandlerAdapter 建立关联关系
handlerAdapters.put(handlerMapping,new HZQHandlerAdapter());
}
}
private void initHandlerExceptionResolvers(HZQApplicationcontext context) {
}
private void initRequestToViewNameTranslator(HZQApplicationcontext context) {
}
private void initViewResolvers(HZQApplicationcontext context) {
//拿到模板存放目录
String templateRoot = context.getCongif().getProperty("templateRoot");
String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
File templateRootDir = new File(templateRootPath);
for (File file : templateRootDir.listFiles()) {
this.viewResolvers.add(new HZQViewResolver(templateRoot));
}
}
private void initFlashMapManager(HZQApplicationcontext context) {
}
}
package com.hezhiqin.formework.webmvc.servlet;
import com.hezhiqin.formework.annotation.HZQRequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-10-31 15:26
*/
public class HZQHandlerMapping {
private Object controller;//保存方法对应的实例
private Method method;//保存映射的方法
private Pattern pattern;
private Map<String,Integer> paramIndexMapping;//参数顺序
/**
*构造一个Handler基本的参数
* @param controller
* @param method
*/
public HZQHandlerMapping(Object controller, Method method, Pattern pattern) {
this.controller = controller;
this.method = method;
this.pattern = pattern;
paramIndexMapping = new HashMap<String,Integer>();
putParamIndexMapping(method);
}
private void putParamIndexMapping(Method method) {
// TODO Auto-generated method stub
//提取方法中加了注解的参数
Annotation[] [] pa = method.getParameterAnnotations();
for (int i = 0; i < pa.length; i++) {
for (Annotation a : pa[i]) {
if(a instanceof HZQRequestParam){
String paramName = ((HZQRequestParam) a).value();
if(!"".equals(paramName.trim())){
paramIndexMapping.put(paramName, i);
}
}
}
}
//提取方法中的 request 和 response 参数
Class<?> [] paramsTypes = method.getParameterTypes();
for (int i = 0; i < paramsTypes.length ; i ++) {
Class<?> type = paramsTypes[i];
if(type == HttpServletRequest.class ||
type == HttpServletResponse.class){
paramIndexMapping.put(type.getName(),i);
}
}
}
public Class<?>[] getParamTypes() {
Class<?> [] paramsTypes = method.getParameterTypes();
return paramsTypes;
}
public Object getController() {
return controller;
}
public void setController(Object controller) {
this.controller = controller;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Pattern getPattern() {
return pattern;
}
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
public Map<String, Integer> getParamIndexMapping() {
return paramIndexMapping;
}
public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) {
this.paramIndexMapping = paramIndexMapping;
}
}
package com.hezhiqin.formework.webmvc.servlet;
import com.hezhiqin.formework.annotation.HZQRequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-10-31 16:25
*/
public class HZQHandlerAdapter {
public boolean supports(Object handler){
return (handler instanceof HZQHandlerMapping);
}
public HZQModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
HZQHandlerMapping handlerMapping = (HZQHandlerMapping) handler;
Map<String,Integer> paramIndexMapping = new HashMap<String,Integer>();
Method method = handlerMapping.getMethod();
//提取方法中加了注解的参数
Annotation[] [] pa = method.getParameterAnnotations();
for (int i = 0; i < pa.length; i++) {
for (Annotation a : pa[i]) {
if(a instanceof HZQRequestParam){
String paramName = ((HZQRequestParam) a).value();
if(!"".equals(paramName.trim())){
paramIndexMapping.put(paramName, i);
}
}
}
}
//提取方法中的 request 和 response 参数
Class<?> [] paramsTypes = method.getParameterTypes();
for (int i = 0; i < paramsTypes.length ; i ++) {
Class<?> type = paramsTypes[i];
if(type == HttpServletRequest.class ||
type == HttpServletResponse.class){
paramIndexMapping.put(type.getName(),i);
}
}
//获得方法的形参列表
Map<String,String[]> params = request.getParameterMap();
//实参列表
Object [] paramValues = new Object[paramsTypes.length];
for (Map.Entry<String, String[]> parm : params.entrySet()) {
String value = Arrays.toString(parm.getValue()).replaceAll("\\[|\\]","")
.replaceAll("\\s",",");
if(!paramIndexMapping.containsKey(parm.getKey())){continue;}
int index = paramIndexMapping.get(parm.getKey());
paramValues[index] = caseStringValue(value,paramsTypes[index]);
}
if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {
int reqIndex = paramIndexMapping.get(HttpServletRequest.class.getName());
paramValues[reqIndex] = request;
}
if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {
int respIndex = paramIndexMapping.get(HttpServletResponse.class.getName());
paramValues[respIndex] = response;
}
Object returnValue = method.invoke(handlerMapping.getController(),paramValues);
if(returnValue == null || returnValue instanceof Void){ return null; }
if (method.getReturnType()==HZQModelAndView.class){
return (HZQModelAndView) returnValue;
}
return null;
}
private Object caseStringValue(String value, Class<?> paramsType) {
if (String.class == paramsType){
return value;
}
if(Integer.class == paramsType){
return Integer.valueOf(value);
}else if(Double.class == paramsType){
return Double.valueOf(value);
}else {
if (value!=null){
return value.toString();
}
return null;
}
}
}
package com.hezhiqin.formework.webmvc.servlet;
import java.util.Map;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-10-31 16:28
*/
public class HZQModelAndView {
private String viewName;
private Map<String,?> model;
public HZQModelAndView(String viewName) {
this.viewName = viewName;
}
public HZQModelAndView(String viewName, Map<String, ?> model) {
this.viewName = viewName;
this.model = model;
}
public String getViewName() {
return viewName;
}
public void setViewName(String viewName) {
this.viewName = viewName;
}
public Map<String, ?> getModel() {
return model;
}
public void setModel(Map<String, ?> model) {
this.model = model;
}
}
package com.hezhiqin.formework.webmvc.servlet;
import java.io.File;
import java.util.Locale;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-01 11:48
*/
public class HZQViewResolver {
private File templateRootDir;
private final String DEFAULT_TEMPLATE_SUFFX = "html";
public HZQViewResolver(String templateRoot) {
String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
templateRootDir = new File(templateRootPath);
}
public HZQView resolveViewName(String viewName, Locale locale) throws Exception{
//viewName 解析成文件
if (viewName==null||"".equals(viewName)){
return null;
}
viewName = viewName.endsWith(DEFAULT_TEMPLATE_SUFFX)?viewName:(viewName+".html");
File templatefile = new File((templateRootDir.getPath()+"/"+viewName).replaceAll("/+","/"));
return new HZQView(templatefile);
}
public File getTemplateRootDir() {
return templateRootDir;
}
public void setTemplateRootDir(File templateRootDir) {
this.templateRootDir = templateRootDir;
}
}
package com.hezhiqin.formework.webmvc.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-01 11:51
*/
public class HZQView {
private final String DEFULAT_CONTENT_TYPE = "text/html;charset=utf-8";
private File viewFile;
public HZQView(File viewFile) {
this.viewFile = viewFile;
}
//
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception{
StringBuffer stringBuffer = new StringBuffer();
//占位符替换成我们想要的字符
RandomAccessFile raf = new RandomAccessFile(viewFile,"r");
String line = null;
while (null!=(line = raf.readLine())){
line = new String(line.getBytes("ISO-8859-1"),"UTF-8");
Pattern pattern = Pattern.compile("¥\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(line);
while (matcher.find()){
String paramName = matcher.group();
paramName = paramName.replaceAll("¥\\{|\\}","");
Object oparamValue = model.get(paramName);
if (null==oparamValue){
continue;
}
line = matcher.replaceFirst(makeStringForRegExp(oparamValue.toString()));
matcher = pattern.matcher(line);
}
stringBuffer.append(line);
}
response.setCharacterEncoding("utf-8");
response.getWriter().write(stringBuffer.toString());
}
//处理特殊字符
public static String makeStringForRegExp(String str) {
return str.replace("\\", "\\\\").replace("*", "\\*")
.replace("+", "\\+").replace("|", "\\|")
.replace("{", "\\{").replace("}", "\\}")
.replace("(", "\\(").replace(")", "\\)")
.replace("^", "\\^").replace("$", "\\$")
.replace("[", "\\[").replace("]", "\\]")
.replace("?", "\\?").replace(",", "\\,")
.replace(".", "\\.").replace("&", "\\&");
}
}
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>咕泡学院SpringMVC模板引擎演示</title>
</head>
<center>
<h1>大家好,我是¥{teacher}老师<br/>欢迎大家一起来探索Spring的世界</h1>
<h3>Hello,My name is ¥{teacher}</h3>
<div>¥{data}</div>
Token值:¥{token}
</center>
</html>
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>页面去火星了</title>
</head>
<body>
<font size='25' color='red'>404 Not Found</font><br/><font color='green'><i>Copyright@GupaoEDU</i></font>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>服务器好像累了</title>
</head>
<body>
<font size='25' color='blue'>500 服务器好像有点累了,需要休息一下</font><br/>
<b>Message:¥{detail}</b><br/>
<b>StackTrace:¥{stackTrace}</b><br/>
<font color='green'><i>Copyright@GupaoEDU</i></font>
</body>
</html>
1.之前的IOC和DI都已经在HZQDispathcherServlet的 init方法中实现了
2.初始化9大组件。
2.1 initHandlerMappings将url和获取 Method 进行配对,
2.2 初始化参数适配器。一个HandlerMapping对应一个HZQHandlerAdapter 保存在Map
2.3初始化视图转换器
将模板(html页面)保存在视图解析器里
3.网页调用时候其实是调用的HZQDispathcherServlet中的doDispather方法
package com.hezhiqin.formework.aop;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-05 14:12
*/
//默认就用JDK 动态代理
public interface HZQAopProxy {
Object getProxy();
Object getProxy(ClassLoader classLoader);
}
public class HZQJdkDynamicAopProxy implements HZQAopProxy,InvocationHandler{
private HZQAdvisedSupport advised;
public HZQJdkDynamicAopProxy(HZQAdvisedSupport config){
this.advised = config;
}
@Override
public Object getProxy() {
return getProxy(this.advised.getTargetClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
return Proxy.newProxyInstance(classLoader,this.advised.getTargetClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
List<Object> interceptorsAndDynamicMethodMatchers = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,this.advised.getTargetClass());
HZQMethodInvocation hzqMethodInvocation = new HZQMethodInvocation(proxy,this.advised.getTarget(),method,args,this.advised.getTargetClass(),interceptorsAndDynamicMethodMatchers);
return hzqMethodInvocation.proceed();
}
}
package com.hezhiqin.formework.aop.support;
import com.hezhiqin.formework.aop.aspect.HZQAfterReturningAdviceInterceptor;
import com.hezhiqin.formework.aop.aspect.HZQAfterThrowingAdviceInterceptor;
import com.hezhiqin.formework.aop.aspect.HZQMethodBeforeAdviceInterceptor;
import com.hezhiqin.formework.aop.config.HZQAopConfig;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-05 14:20
*/
public class HZQAdvisedSupport {
private Object target;
private Class<?> targetClass;
private HZQAopConfig config;
private Pattern pointCutClassPattern;
private transient Map<Method, List<Object>> methodCache;
public HZQAdvisedSupport(HZQAopConfig config) {
this.config = config;
}
public Class<?> getTargetClass(){
return this.targetClass;
}
public void setTargetClass(Class<?> targetClass) {
this.targetClass = targetClass;
parse();
}
public Object getTarget(){
return this.target;
}
public void setTarget(Object target) {
this.target = target;
}
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) throws Exception{
List<Object> cached = methodCache.get(method);
if(cached==null){
Method m = targetClass.getMethod(method.getName(),method.getParameterTypes());
cached = methodCache.get(m);
//底层逻辑,对代理方法进行一个兼容处理
this.methodCache.put(m,cached);
}
return cached;
}
public boolean pointCutMatch() {
return pointCutClassPattern.matcher(this.targetClass.toString()).matches();
}
private void parse() {
String pointCut = config.getPointCut()
.replaceAll("\\.","\\\\.")
.replaceAll("\\\\.\\*",".*")
.replaceAll("\\(","\\\\(")
.replaceAll("\\)","\\\\)");
//pointCut=public .* com.gupaoedu.vip.spring.demo.service..*Service..*(.*)
//玩正则,完整的匹配传入的类是否匹配切点规则
String pointCutForClassRegex = pointCut.substring(0,pointCut.lastIndexOf("\\(") - 4);
pointCutClassPattern = Pattern.compile("class " + pointCutForClassRegex.substring(
pointCutForClassRegex.lastIndexOf(" ") + 1));
try {
methodCache = new HashMap<Method, List<Object>>();
Pattern pattern = Pattern.compile(pointCut);
Class aspectClass = Class.forName(this.config.getAspectClass());
Map<String,Method> aspectMethods = new HashMap<String,Method>();
for (Method m : aspectClass.getMethods()) {//切面的方法
aspectMethods.put(m.getName(),m);
}
for (Method m : this.targetClass.getMethods()) {//切面的方法
String methodString = m.toString();
if (methodString.contains("throws")) {
methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim();
}
Matcher matcher = pattern.matcher(methodString);
if(matcher.matches()){
//执行器链
List<Object> advices = new LinkedList<Object>();
//把每一个方法包装成 MethodInterceptor
//before
if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
//创建一个Advivce
advices.add(new HZQMethodBeforeAdviceInterceptor(aspectMethods.get(config.getAspectBefore()),aspectClass.newInstance()));
}
//after
if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
//创建一个Advivce
advices.add(new HZQAfterReturningAdviceInterceptor(aspectMethods.get(config.getAspectAfter()),aspectClass.newInstance()));
}
//afterThrowing
if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))) {
//创建一个Advivce
HZQAfterThrowingAdviceInterceptor throwingAdvice =
new HZQAfterThrowingAdviceInterceptor(
aspectMethods.get(config.getAspectAfterThrow()),
aspectClass.newInstance());
throwingAdvice.setThrowName(config.getAspectAfterThrowingName());
advices.add(throwingAdvice);
}
methodCache.put(m,advices);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
package com.hezhiqin.formework.aop.intercept;
import com.hezhiqin.formework.aop.aspect.HZQJoinPoint;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-06 13:27
*/
public class HZQMethodInvocation implements HZQJoinPoint {
private Object proxy;
private Method method;
private Object target;
private Object [] arguments;
private List<Object> interceptorsAndDynamicMethodMatchers;
private Class<?> targetClass;
private Map<String, Object> userAttributes;
//定义一个索引,从-1开始来记录当前拦截器执行的位置
private int currentInterceptorIndex = -1;
public HZQMethodInvocation(
Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = method;
this.arguments = arguments;
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//如果Interceptor 执行完了,则执行joinPoint
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return this.method.invoke(this.target,this.arguments);
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果要动态匹配joinPoint
if (interceptorOrInterceptionAdvice instanceof HZQMethodInterceptor) {
HZQMethodInterceptor mi =
(HZQMethodInterceptor) interceptorOrInterceptionAdvice;
return mi.invoke(this);
} else {
//动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor
return proceed();
}
}
@Override
public Object getThis() {
return this;
}
@Override
public Object[] getArguments() {
return arguments;
}
@Override
public Method getMethod() {
return method;
}
@Override
public void setUserAttribute(String key, Object value) {
if (value != null) {
if (this.userAttributes == null) {
this.userAttributes = new HashMap<String,Object>();
}
this.userAttributes.put(key, value);
}
else {
if (this.userAttributes != null) {
this.userAttributes.remove(key);
}
}
}
@Override
public Object getUserAttribute(String key) {
return (this.userAttributes != null ? this.userAttributes.get(key) : null);
}
}
package com.hezhiqin.formework.aop.intercept;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-06 13:48
*/
public interface HZQMethodInterceptor {
Object invoke(HZQMethodInvocation invocation) throws Throwable;
}
package com.hezhiqin.formework.aop.aspect;
public interface HZQAdvice {
}
package com.hezhiqin.formework.aop.aspect;
import java.lang.reflect.Method;
/**
* Created by Tom on 2019/4/15.
*/
public interface HZQJoinPoint {
Object getThis();
Object[] getArguments();
Method getMethod();
void setUserAttribute(String key, Object value);
Object getUserAttribute(String key);
}
package com.hezhiqin.formework.aop.config;
import lombok.Data;
/**
* @program: homeWork
* @description: 对应配置文件
* @author: hezhiqin
* @create: 2019-11-06 14:44
*/
@Data
public class HZQAopConfig {
private String pointCut;
private String aspectClass;
private String aspectBefore;
private String aspectAfter;
private String aspectAfterThrow;
private String aspectAfterThrowingName;
}
package com.hezhiqin.formework.aop.aspect;
import java.lang.reflect.Method;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-06 16:06
*/
public abstract class HZQAbstractAspectAdvice implements HZQAdvice {
private Method aspectMethod;
private Object aspectTarget;
public HZQAbstractAspectAdvice(Method aspectMethod, Object aspectTarget) {
this.aspectMethod = aspectMethod;
this.aspectTarget = aspectTarget;
}
protected Object invokeAdviceMethod(HZQJoinPoint joinPoint, Object returnValue, Throwable tx)throws Throwable{
Class<?> [] paramTypes = this.aspectMethod.getParameterTypes();
if(null == paramTypes || paramTypes.length == 0){
return this.aspectMethod.invoke(aspectTarget);
}else{
Object [] args = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i ++) {
if(paramTypes[i] == HZQJoinPoint.class){
args[i] = joinPoint;
}else if(paramTypes[i] == Throwable.class){
args[i] = tx;
}else if(paramTypes[i] == Object.class){
args[i] = returnValue;
}
}
return this.aspectMethod.invoke(aspectTarget,args);
}
}
}
package com.hezhiqin.formework.aop.aspect;
import com.hezhiqin.formework.aop.intercept.HZQMethodInterceptor;
import com.hezhiqin.formework.aop.intercept.HZQMethodInvocation;
import java.lang.reflect.Method;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-06 15:58
*/
public class HZQMethodBeforeAdviceInterceptor extends HZQAbstractAspectAdvice implements HZQMethodInterceptor {
private HZQJoinPoint joinPoint;
public HZQMethodBeforeAdviceInterceptor(Method aspectMethod, Object aspectTarget) {
super(aspectMethod, aspectTarget);
}
private void before(Method method,Object[] args,Object target) throws Throwable{
super.invokeAdviceMethod(this.joinPoint,null,null);
}
@Override
public Object invoke(HZQMethodInvocation invocation) throws Throwable {
this.joinPoint = invocation;
before(invocation.getMethod(), invocation.getArguments(), invocation.getThis());
return invocation.proceed();
}
}
package com.hezhiqin.formework.aop.aspect;
import com.hezhiqin.formework.aop.intercept.HZQMethodInterceptor;
import com.hezhiqin.formework.aop.intercept.HZQMethodInvocation;
import java.lang.reflect.Method;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-06 15:58
*/
public class HZQAfterReturningAdviceInterceptor extends HZQAbstractAspectAdvice implements HZQMethodInterceptor {
private HZQJoinPoint joinPoint;
public HZQAfterReturningAdviceInterceptor(Method aspectMethod, Object aspectTarget) {
super(aspectMethod, aspectTarget);
}
private void afterReturning(Object retVal, Method method, Object[] arguments, Object aThis) throws Throwable {
super.invokeAdviceMethod(this.joinPoint,retVal,null);
}
@Override
public Object invoke(HZQMethodInvocation invocation) throws Throwable {
Object retVal = invocation.proceed();
this.joinPoint = invocation;
afterReturning(retVal, invocation.getMethod(), invocation.getArguments(),invocation.getThis());
return retVal;
}
}
package com.hezhiqin.formework.aop.aspect;
import com.hezhiqin.formework.aop.intercept.HZQMethodInterceptor;
import com.hezhiqin.formework.aop.intercept.HZQMethodInvocation;
import java.lang.reflect.Method;
/**
* @program: homeWork
* @description:
* @author: hezhiqin
* @create: 2019-11-06 16:00
*/
public class HZQAfterThrowingAdviceInterceptor extends HZQAbstractAspectAdvice implements HZQMethodInterceptor {
private String throwName;
public HZQAfterThrowingAdviceInterceptor(Method aspectMethod, Object aspectTarget) {
super(aspectMethod, aspectTarget);
}
public void setThrowName(String throwName) {
this.throwName = throwName;
}
@Override
public Object invoke(HZQMethodInvocation invocation) throws Throwable {
try {
return invocation.proceed();
}catch (Throwable e){
invokeAdviceMethod(invocation,null,e.getCause());
throw e;
}
}
}
找到GPApplicationContext 的getBean()方法,我们知道getBean()中负责Bean 初始化的方法其实就是instantiateBean(),我们在初始化时就可以确定是否返回原生Bean 还是Proxy Bean。代码实现
至此我们就创建了一个代理对象 在这里有一个很关键的方法,这是怕被切点的方法和LogAspect 配置的方法绑定
private void parse() {
String pointCut = config.getPointCut()
.replaceAll("\\.","\\\\.")
.replaceAll("\\\\.\\*",".*")
.replaceAll("\\(","\\\\(")
.replaceAll("\\)","\\\\)");
//pointCut=public .* com.gupaoedu.vip.spring.demo.service..*Service..*(.*)
//玩正则,完整的匹配传入的类是否匹配切点规则
String pointCutForClassRegex = pointCut.substring(0,pointCut.lastIndexOf("\\(") - 4);
pointCutClassPattern = Pattern.compile("class " + pointCutForClassRegex.substring(
pointCutForClassRegex.lastIndexOf(" ") + 1));
try {
methodCache = new HashMap<Method, List<Object>>();
Pattern pattern = Pattern.compile(pointCut);
Class aspectClass = Class.forName(this.config.getAspectClass());
Map<String,Method> aspectMethods = new HashMap<String,Method>();
for (Method m : aspectClass.getMethods()) {//切面的方法
aspectMethods.put(m.getName(),m);
}
for (Method m : this.targetClass.getMethods()) {//切面的方法
String methodString = m.toString();
if (methodString.contains("throws")) {
methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim();
}
Matcher matcher = pattern.matcher(methodString);
if(matcher.matches()){
//执行器链
List<Object> advices = new LinkedList<Object>();
//把每一个方法包装成 MethodInterceptor
//before
if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
//创建一个Advivce
advices.add(new HZQMethodBeforeAdviceInterceptor(aspectMethods.get(config.getAspectBefore()),aspectClass.newInstance()));
}
//after
if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
//创建一个Advivce
advices.add(new HZQAfterReturningAdviceInterceptor(aspectMethods.get(config.getAspectAfter()),aspectClass.newInstance()));
}
//afterThrowing
if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))) {
//创建一个Advivce
HZQAfterThrowingAdviceInterceptor throwingAdvice =
new HZQAfterThrowingAdviceInterceptor(
aspectMethods.get(config.getAspectAfterThrow()),
aspectClass.newInstance());
throwingAdvice.setThrowName(config.getAspectAfterThrowingName());
advices.add(throwingAdvice);
}
methodCache.put(m,advices);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
那么在调用时会调用 HZQJdkDynamicAopProxy 中的 invoke方法
这里巧妙在proceed的执行顺序上
1.先在HZQMethodInvocation定义一个索引
//定义一个索引,从-1开始来记录当前拦截器执行的位置
private int currentInterceptorIndex = -1;
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//如果Interceptor 执行完了,则执行joinPoint
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return this.method.invoke(this.target,this.arguments);
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果要动态匹配joinPoint
if (interceptorOrInterceptionAdvice instanceof HZQMethodInterceptor) {
HZQMethodInterceptor mi =
(HZQMethodInterceptor) interceptorOrInterceptionAdvice;
return mi.invoke(this);
} else {
//动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor
return proceed();
}
}