以下版本都是简易版,后期将会更新更完整的版本
版本一:面对过程化,简易实现Spring ioc DI与Spring MVC
由于面试过程版,简单,不多说,贴部分代码,明眼人一看就懂
先带上目录结构:
首先我们知道,web.xml是mvc项目的启动点。我们配置自己的Servlet。
回到我们自己定义的Servlet中进行业务:
init关键的步骤:
//1、加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
//2、扫描相关的类
doScanner(contextConfig.getProperty("scanPackage"));
//3、初始化扫描到的类,并且放入到IOC容器之中
doInstance();
//========= DI =========
//4、完成自动化的依赖注入
doAutowired();
//======= MVC =============
//5、初始化HandlerMapping
doInitHandlerMapping();
定义常规容器:
//保存application.properties配置文件中的内容
private Properties contextConfig = new Properties();
//保存扫描的所有的类名
private List<String> classNames = new ArrayList<String>();
//为了简化程序,暂时不考虑ConcurrentHashMap
// 主要还是关注设计思想和原理
private Map<String,Object> ioc = new HashMap<String,Object>();
//保存url和Method的对应关系
private Map<String,Method> handlerMapping = new HashMap<String,Method>();
准备就绪:
```java
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//6、根据url调用method
try {
doDispatch(req,resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500 Exception,Detail: " + Arrays.toString(e.getStackTrace()));
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replaceAll(contextPath,"").replaceAll("/+","/");
if(!this.handlerMapping.containsKey(url)){
resp.getWriter().write("404 Not Found!!");
return;
}
Method method = this.handlerMapping.get(url);
Map<String,String[]> paramsMap = req.getParameterMap();
//实参列表
//实参列表要根据形参列表才能决定,首先得拿到形参列表
Class<?> [] paramterTypes = method.getParameterTypes();
Object [] parameValues = new Object[paramterTypes.length];
for (int i = 0; i <paramterTypes.length; i ++){
Class paramterType = paramterTypes[i];
if(paramterType == HttpServletRequest.class){
parameValues[i] = req;
continue;
}else if(paramterType == HttpServletResponse.class){
parameValues[i] = resp;
continue;
}else if(paramterType == String.class){
Annotation[][] pa = method.getParameterAnnotations();
System.out.println("debug.....");
for (int j = 0; j < pa.length; j ++){
for (Annotation a : pa[i]) {
if(a instanceof RequestParam){
String paramName = ((RequestParam) a).value();
if(!"".equals(paramName.trim())){
String value = Arrays.toString(paramsMap.get(paramName))
.replaceAll("\\[|\\]","") //正则处理[]
.replaceAll("\\s",","); //正则处理空格
parameValues[i] = value;
}
}
}
}
}
}
String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
method.invoke(ioc.get(beanName),parameValues);
}
`
第二版;面对对象版 实现spring ioc ,aop,DI mvc
我们先来完成 ioc 与DI .
我们先来定义几个类:
核心类:ApplicationContext
存放配置文件类: BeanDefintion
加载处理配置文件的的类: BeanDefintionReader
保存实例:BeanWrapper
public class BeanDefinition {
//key值
private String factoryBeanName;
//全限定名
private String beanClassName; }
public class BeanWrapper {
private Object wrapperInstance;
private Class<?> wrappedClass;
}
init当中的除了handle,别的都需要到application里来处理:
application的容器:
先聊一聊步骤然后直接贴代码
第一步加载配置文件扫描对应的包 生成BeanDeFinition的map。
第二,这里我使用的是加ioc容器和注入同时进入,详见getBean;逻辑,这样能在初始化阶段没有注入完成,但是不碍事,因为后面我们需要用的实例的时候,会调用getbean。
这样差不多,ioc,di就完成了
public class ApplicationContext {
private String [] configLoactions;
//bean的配置容器
private final Map<String,BeanDefinition> beanDefinitionMap = new HashMap<String,BeanDefinition>();
private BeanDefinitionReader reader;
//真正的ioc容器
private Map<String,BeanWrapper> factoryBeanInstanceCache = new HashMap<String,BeanWrapper>();
private Map<String,Object> factoryBeanObjectCache = new HashMap<String, Object>();
public ApplicationContext(String... configLocations){
this.configLoactions = configLocations;
try {
//1读取配置文件
reader =new BeanDefinitionReader(this.configLoactions);
//2、解析配置文件,封装成BeanDefinition
List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
//3、把BeanDefinition对应的实例放入
doRegisterBeanDefinition(beanDefinitions);
//4、完成依赖注入
doAutowrited();
}catch (Exception e){
e.printStackTrace();
}
}
private void doAutowrited() {
//依赖注入的第一步
//是不是先得根据配置把对象的实例搞出来,才有可能依赖注入
for (Map.Entry<String,BeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()) {
String beanName = beanDefinitionEntry.getKey();
getBean(beanName);
}
}
public Object getBean(String beanName){
//1、读取GPBeanDefinition的配置信息
BeanDefinition gpBeanDefinition = this.beanDefinitionMap.get(beanName);
//2、用反射实例化
Object instance = instantiateBean(beanName,gpBeanDefinition);
//3、把创建出来的真实的实例包装为BeanWrapper对象
BeanWrapper beanWrapper = new BeanWrapper(instance);
//循环依赖
//class A{B b;}
//class B{A a;}
//4、把BeanWrapper对象放入到真正的IOC容器里面
this.factoryBeanInstanceCache.put(beanName,beanWrapper);
//5、执行依赖注入
populateBean(beanName,new BeanDefinition(),beanWrapper);
return this.factoryBeanInstanceCache.get(beanName).getWrapperInstance();
}
public Properties getConfig(){
return this.reader.getConfig();
}
private void populateBean(String beanName, BeanDefinition gpBeanDefinition, BeanWrapper beanWrapper) {
Object instance = beanWrapper.getWrapperInstance();
Class<?> clazz = beanWrapper.getWrappedClass();
//只有加了注解的才进行依赖注入
if(!(clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(Service.class))){
return;
}
//拿到实例的所有的字段
// //Declared 所有的,特定的 字段,包括private/protected/default
// //正常来说,普通的OOP编程只能拿到public的属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Autowired.class)) {
continue;
}
Autowired autowired = field.getAnnotation(Autowired.class);
//如果用户没有自定义beanName,默认就根据类型注入
//这个地方省去了对类名首字母小写的情况的判断,这个作为课后作业
//小伙伴们自己去完善
String autowiredBeanName = autowired.value().trim();
if ("".equals(autowiredBeanName)) {
//获得接口的类型,作为key待会拿这个key到ioc容器中去取值
autowiredBeanName = field.getType().getName();
}
//如果是public以外的修饰符,只要加了@Autowired注解,都要强制赋值
//反射中叫做暴力访问, 强吻
field.setAccessible(true);
//反射调用的方式
//给entry.getValue()这个对象的field字段,赋ioc.get(beanName)这个值
try {
if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) {
continue;
}
field.set(instance, this.factoryBeanInstanceCache.get(autowiredBeanName).getWrapperInstance());
} catch (IllegalAccessException e) {
e.printStackTrace();
continue;
}
}
}
private Object instantiateBean(String beanName, BeanDefinition gpBeanDefinition) {
String className = gpBeanDefinition.getBeanClassName();
Object instance = null;
try {
Class<?> clazz = Class.forName(className);
instance = clazz.newInstance();
//1、读取通知和目标类的关联关系
AdvisedSupport config = instantionAopConfig(gpBeanDefinition);
config.setTargetClass(clazz);
config.setTarget(instance);
// /2、生成一个代理类
//不是所有的类都会生成代理类
if(config.pointCutMatch()) {
instance = new JdkDynamicAopProxy(config).getProxy();
}
this.factoryBeanObjectCache.put(beanName,instance);
// this.factoryBeanObjectCache.put(gpBeanDefinition.getFactoryBeanName(),instance);
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
private AdvisedSupport instantionAopConfig(BeanDefinition gpBeanDefinition) {
AopConfig config = new AopConfig();
config.setPointCut(this.reader.getConfig().getProperty("pointCut"));
config.setAspectClass(this.reader.getConfig().getProperty("aspectClass"));
config.setAspectBefore(this.reader.getConfig().getProperty("aspectBefore"));
config.setAspectAfter(this.reader.getConfig().getProperty("aspectAfter"));
config.setAspectAfterThrow(this.reader.getConfig().getProperty("aspectAfterThrow"));
config.setAspectAfterThrowingName(this.reader.getConfig().getProperty("aspectAfterThrowingName"));
return new AdvisedSupport(config);
}
private void doRegisterBeanDefinition(List<BeanDefinition> beanDefinitions) throws Exception{
for (BeanDefinition beanDefinition : beanDefinitions) {
if(this.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())){
throw new Exception("The " + beanDefinition.getFactoryBeanName() + " is exists");
}
this.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);
// this.beanDefinitionMap.put(beanDefinition.getBeanClassName(),beanDefinition);
}
}
public int getBeanDefinitionCount(){
return beanDefinitionMap.size();
}
//获得IOC容器中所有的beanName的名字
public String[] getBeanDefinitionNames(){
return beanDefinitionMap.keySet().toArray(new String[this.beanDefinitionMap.size()]);
}
public Object getBean(Class beanClass){
return getBean(beanClass.getName());
}
}
public class BeanDefinitionReader {
private List<String> registryBeanClasses = new ArrayList<String>();
private Properties contextConfig = new Properties();
public BeanDefinitionReader(String[] configLoactions) {
//直接从类路径下找到Spring主配置文件所在的路径
//并且将其读取出来放到Properties对象中
//相对于scanPackage=com.gupaoedu.demo 从文件中保存到了内存中
InputStream inputStream=this.getClass().getClassLoader().getResourceAsStream(configLoactions[0].replaceAll("classpath:","")) ;
try {
contextConfig.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}finally {
if (null!=inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
doScanner(contextConfig.getProperty("scanPackage"));
}
private void doScanner(String scanPackage) {
URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
File classPath = new File(url.getFile());
for (File file : classPath.listFiles()) {
if(file.isDirectory()){
doScanner(scanPackage + "." + file.getName());
}else {
//变成包名.类名
//Class.forname()
if (!file.getName().endsWith(".class")) { continue; }
String className = scanPackage + "." + file.getName().replace(".class", "");
//classNames.add();
registryBeanClasses.add(className);
}
}
}
private String toLowerFirstCase(String simpleName) {
char [] chars = simpleName.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
public List<BeanDefinition> loadBeanDefinitions() {
List<BeanDefinition> beanDefinitions=new ArrayList<>();
try {
for (String className : registryBeanClasses) {
Class<?> beanClass = Class.forName(className);
if (beanClass.isInterface()){continue;}
//1、默认类名首字母小
// 2、自定义名字
beanDefinitions.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()),beanClass.getName()));
//3、接口注入
for (Class<?> i : beanClass.getInterfaces()) {
beanDefinitions.add(doCreateBeanDefinition(i.getName(),beanClass.getName()));
}
}
}catch (Exception e){
e.printStackTrace();
}
return beanDefinitions;
}
private BeanDefinition doCreateBeanDefinition(String fatoryBeanName, String beanClassName) {
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName(beanClassName);
beanDefinition.setFactoryBeanName(fatoryBeanName);
return beanDefinition;
}
public Properties getConfig() {
return contextConfig;
}
}
我们再来完成mvc
核心类:DispatcherServlet
处理URL 与方法的绑定:
public class HandlerMapping {
protected Object controller; //保存方法对应的实例
protected Method method; //保存映射的方法
protected Pattern pattern;
每个hander对应的参数处理器: HandlerAdapter,处理完后返回 ModelAndView
ModelAndView:方法返回包装类型
view:将数据处理模板文件板文件,读取,替换,然后返回给浏览器
ViewResolver:视图解析器,根据返回的约定,找到对应的ht模板文件给view
先提思路,然后直接上代码。
public class DispatcherServlet extends HttpServlet {
ApplicationContext applicationContext = null;
//保存url和Method的对应关系
private List<HandlerMapping> handlerMappings = new ArrayList<HandlerMapping>();
//
private Map<HandlerMapping,HandlerAdapter> handlerAdapters = new HashMap<HandlerMapping, HandlerAdapter>();
private List<ViewResolver> viewResolvers = new ArrayList<ViewResolver>();
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//6、根据url调用method
try {
doDispatch(req,resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500 Exception,Detail: " + Arrays.toString(e.getStackTrace()));
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
//1、根据url拿到对应的Handler
HandlerMapping handler = getHandler(req);
if(null == handler){
processDispatchResult(req,resp,new ModelAndView("404"));
return;
}
//2、根据HandlerMapping拿到HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(handler);
//3、根据HandlerApdater拿到ModelAndView
ModelAndView mv = ha.handle(req,resp,handler);
//4、ViewResolver 拿到View
//将View 渲染成浏览器能够接收的结果 HTML字符串
processDispatchResult(req,resp,mv);
}
private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, ModelAndView mv) throws Exception {
if(null == mv){return;}
if(this.viewResolvers.isEmpty()){return;}
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(mv.getViewName());
view.render(mv.getModel(),req,resp);
return;
}
}
private HandlerAdapter getHandlerAdapter(HandlerMapping handler) {
if(this.handlerAdapters.isEmpty()){return null;}
HandlerAdapter ha = this.handlerAdapters.get(handler);
return ha;
}
private HandlerMapping getHandler(HttpServletRequest req) {
if (this.handlerMappings.isEmpty()){return null;}
String url=req.getRequestURI();
String contextPath=req.getContextPath();
url = url.replaceAll(contextPath,"").replaceAll("/+","/");
for (HandlerMapping handlerMapping : this.handlerMappings) {
Matcher matcher = handlerMapping.getPattern().matcher(url);
//url是用正则去匹配Controller中的配置信息
if(!matcher.matches()){continue;}
return handlerMapping;
}
return null;
}
public void init(ServletConfig config) throws ServletException {
applicationContext = new ApplicationContext(config.getInitParameter("contextConfigLocation"));
//初始化Spring MVC的九大组件,今天只实现
//HandlerMapping
//HandlerAdapter
//ViewResolver
initStrategies(applicationContext);
System.out.println("GP Spring framework is init.");
}
private void initStrategies(ApplicationContext context) {
//Url和Method的对应关系
initHandlerMappings(context);
//参数适配器
initHandlerAdaters(context);
//视图转换器
initViewResolvers(context);
}
private void initViewResolvers(ApplicationContext context) {
String templateRoot = context.getConfig().getProperty("templateRoot");
String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
File templateRootDir = new File(templateRootPath);
for (File file : templateRootDir.listFiles()) {
//高仿真
this.viewResolvers.add(new ViewResolver(templateRoot));
}
}
private void initHandlerMappings(ApplicationContext context) {
String [] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
Object instance = context.getBean(beanName);
Class<?> clazz = instance.getClass();
if (!clazz.isAnnotationPresent(Controller.class)) {
continue;
}
//保存写在类上面的@GPRequestMapping("/demo")
String baseUrl = "";
if(clazz.isAnnotationPresent(RequestMapping.class)){
RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
baseUrl = requestMapping.value();
}
//默认获取所有的public方法
for (Method method : clazz.getMethods()) {
if(!method.isAnnotationPresent(RequestMapping.class)){continue;}
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
//demoquery
// //demo//query
String regex = ("/" + baseUrl + "/" + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+","/");
Pattern pattern = Pattern.compile(regex);
this.handlerMappings.add(new HandlerMapping(instance,method,pattern));
System.out.println("Mapped " + regex + "," + method);
}
}
}
private void initHandlerAdaters(ApplicationContext context) {
for (HandlerMapping handlerMapping : handlerMappings) {
this.handlerAdapters.put(handlerMapping,new HandlerAdapter());
}
}
}
public class HandlerAdapter {
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, HandlerMapping handler) throws Exception{
//拼接形参列表
//保存了Controller的方法上配置的参数名字以及和参数位置的对应关系
Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();
//提取方法中加了注解的参数
Annotation[] [] pa = handler.getMethod().getParameterAnnotations();
for (int i = 0; i < pa.length ; i ++) {
for(Annotation a : pa[i]){
if(a instanceof RequestParam){
String paramName = ((RequestParam) a).value();
if(!"".equals(paramName.trim())){
paramIndexMapping.put(paramName, i);
}
}
}
}
//提取方法中的request和response参数
Class<?> [] paramsTypes = handler.getMethod().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[]> paramsMap = request.getParameterMap();
Object [] parameValues = new Object[paramsTypes.length];
for (Map.Entry<String, String[]> param : paramsMap.entrySet()) {
String value = Arrays.toString(paramsMap.get(param.getKey()))
.replaceAll("\\[|\\]","")
.replaceAll("\\s",",");
if(!paramIndexMapping.containsKey(param.getKey())){continue;}
int index = paramIndexMapping.get(param.getKey());
parameValues[index] = caseStringValue(value,paramsTypes[index]);
}
if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
int index = paramIndexMapping.get(HttpServletRequest.class.getName());
parameValues[index] = request;
}
if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
int index = paramIndexMapping.get(HttpServletResponse.class.getName());
parameValues[index] = response;
}
Object result = handler.getMethod().invoke(handler.getController(),parameValues);
if(result == null || result instanceof Void){return null;}
boolean isModelAndView = handler.getMethod().getReturnType() == ModelAndView.class;
if(isModelAndView){
return (ModelAndView)result;
}
return null;
}
private Object caseStringValue(String value,Class<?> paramType){
if(String.class == paramType){
return value;
}
if(Integer.class == paramType){
return Integer.valueOf(value);
}else if(Double.class == paramType){
return Double.valueOf(value);
} else{
if(value != null){
return value;
}
return null;
}
}
package com.itwcxing.spring.framework.servlet;
import java.io.File;
/**
* @Filename
* @auther 吴星辰;
* @data 2020/2/10 16:17;
* @Descripion
* @Version 1.1.1
* @Function
* @History
*/
public class ViewResolver {
//.jsp .vm .ftl
private final String DEAULT_TEMPLATE_SUFFX = ".html";
private File templateRootDir;
public ViewResolver(String teamplateRoot){
String templateRootPath = this.getClass().getClassLoader().getResource(teamplateRoot).getFile();
templateRootDir = new File(templateRootPath);
}
public View resolveViewName(String viewName){
if(null == viewName || "".equals(viewName.trim())){return null;}
viewName = viewName.endsWith(DEAULT_TEMPLATE_SUFFX) ? viewName : (viewName + DEAULT_TEMPLATE_SUFFX);
File templateFile = new File((templateRootDir.getPath() + "/" + viewName).replaceAll("/+","/"));
return new View(templateFile);
}
}
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;
/**
* @Filename
* @auther 吴星辰;
* @data 2020/2/10 16:59;
* @Descripion
* @Version 1.1.1
* @Function
* @History
*/
public class View {
private File viewFile;
public View(File templateFile) {
this.viewFile = templateFile;
}
public void render(Map<String,?> model, HttpServletRequest request, HttpServletResponse response) throws Exception{
//第一步,就是把模板文件的内容读出来
StringBuffer sb = new StringBuffer();
RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");
//解析,把模板里面写的模板语言替换掉
String line = null;
while (null != (line = ra.readLine())){
line = new String(line.getBytes("ISO-8859-1"),"utf-8");
Pattern pattern = Pattern.compile("¥\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE); //将 { 中不包含 } } 的逐个匹配
Matcher mather = pattern.matcher(line);
while (mather.find()){
String paramName = mather.group();
paramName = paramName.replaceAll("¥\\{|\\}","");//将 ¥ { } 替换调
Object paramVlue = model.get(paramName);
if(null == paramVlue){continue;}
line = mather.replaceFirst(makeStringForRegExp(paramVlue.toString()));
mather = pattern.matcher(line);
}
sb.append(line);
}
response.setCharacterEncoding("utf-8");
response.getWriter().write(sb.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("&", "\\&");
}
}
再来写一下aop:
首先可以明确的知道
首先我们知道aop就是在加入ioc容器之前完成的,所以基本的思路就有了
在我们反射生成实例加入ioc的时候,判断一下这个方法需不需aop处理就行了。
先来介绍一下我们的类:
AdvisedSupport:处理配置信息和用来处理实际方法与通知先关起来
JdkDynamicAopProxy:实现jdbc代理
流程;
加入ioc容器前,生成AdvisedSupport对象并且导入advisrconfig
配置,目标实例,与类类,并生成正则判断。
然后直接正则判断是不是要aop的类。
如果是 生成目标方法和所有的切入方法对应关系。 jdbc一波就行
//1、读取通知和目标类的关联关系
GPAdvisedSupport config = instantionAopConfig(gpBeanDefinition);
config.setTargetClass(clazz);
config.setTarget(instance);
//2、生成一个代理类
//不是所有的类都会生成代理类
if(config.pointCutMatch()) {
instance = new GPJdkDynamicAopProxy(config).getProxy();
}
public class GPAdvisedSupport {
private Class targetClass;
private Object target;
private GPAopConfig config;
private Pattern pointCutClassPattern;
//用来保存配置文件中对应的Method和Advice的对应关系
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() {
//PonintCut 表达式解析为正则表达式
String pointCut = config.getPointCut()
.replaceAll("\\.","\\\\.")
.replaceAll("\\\\.\\*",".*")
.replaceAll("\\(","\\\\(")
.replaceAll("\\)","\\\\)");
//玩正则
String pointCutForClassRegex = pointCut.substring(0,pointCut.lastIndexOf("\\(") - 4);
pointCutClassPattern = Pattern.compile("class " + pointCutForClassRegex.substring(
pointCutForClassRegex.lastIndexOf(" ") + 1));
try {
methodCache = new HashMap<Method, Map<String, GPAdvice>>();
Pattern pointCutPattern = Pattern.compile(pointCut);
Class apectClass = Class.forName(this.config.getAspectClass());
Map<String,Method> aspectMethods = new HashMap<String,Method>();
for (Method method : apectClass.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> advices = new HashMap<String,GPAdvice>();
if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))){
advices.put("before",new GPAdvice(apectClass.newInstance(),aspectMethods.get(config.getAspectBefore())));
}
if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))){
advices.put("after",new GPAdvice(apectClass.newInstance(),aspectMethods.get(config.getAspectAfter())));
}
if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))){
GPAdvice a = new GPAdvice(apectClass.newInstance(),aspectMethods.get(config.getAspectAfterThrow()));
a.setThrowName(config.getAspectAfterThrowingName());
advices.put("afterThrow",a);
}
methodCache.put(method,advices);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
public Object getTarget() {
return target;
}
public boolean pointCutMatch() {
return pointCutClassPattern.matcher(this.targetClass.toString()).matches();
}
public Map<String,GPAdvice> getAdivces(Method method, Class<?> targetClass) throws Exception{
Map<String,GPAdvice> cached = methodCache.get(method);
//精髓
//如果没找到,就返回自己
if(null == cached){
Method m = targetClass.getMethod(method.getName(),method.getParameterTypes());
cached = methodCache.get(m);
this.methodCache.put(m,cached);
}
return cached;
}
public void setTarget(Object target) {
this.target = target;
}
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() {
return Proxy.newProxyInstance(this.geetClass().getClassLoader(),this.config.getTargetClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Map<String,GPAdvice> advices = this.config.getAdivces(method,this.config.getTargetClass());
Object returnValue = null;
invokeAdivce(advices.get("before"));
try {
returnValue = method.invoke(this.config.getTarget(), args);
}catch (Exception e){
invokeAdivce(advices.get("afterThrow"));
e.printStackTrace();
throw e;
}
invokeAdivce(advices.get("after"));
return returnValue;
}
private void invokeAdivce(GPAdvice advice) {
try {
advice.getAdviceMethod().invoke(advice.getAspect());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}