400-616-5551

您所在位置: 首页> 学习课程> java架构师 | SpringAOP那些无处不在的动态代理

java架构师 | SpringAOP那些无处不在的动态代理

发布百知教育 来源:学习课程 2019-11-29

环境配置


代码结构


1.jpg



pom.xml文件

<?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">
<modelVersion>4.0.0</modelVersion>

<groupId>com.gupaoedu</groupId>
<artifactId>gupaoedu-springaop</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gupaoedu-springaop</name>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</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>

</project>


application.properties文件

#多切面配置可以在key前面加前缀
#例如 aspect.logAspect.
#切面表达式,expression#
pointCut=public .* com.gupaoedu.springaop.demo.service..*Service..*(.*)
#切面类#
aspectClass=com.gupaoedu.springaop.demo.aspect.LogAspect
#切面前置通知#
aspectBefore=before
#切面后置通知#
aspectAfter=after
#切面异常通知#
aspectAfterThrow=afterThrowing
#切面异常类型#
aspectAfterThrowingName=java.lang.Exception


业务代码

Member实体类

package com.gupaoedu.springaop.demo.model;

public class Member {

}


IMermverServer接口

package com.gupaoedu.springaop.demo.service;

import com.gupaoedu.springaop.demo.model.Member;

/**
* 注解版业务操作类
* @author Tom
*/


public interface IMemberService {

public Member get(String id);

public Member get();

public void save(Member member);

public Boolean delete(String id) throws Exception;

}

MemberService业务实现类

package com.gupaoedu.springaop.demo.service.impl;

import com.gupaoedu.springaop.demo.model.Member;
import com.gupaoedu.springaop.demo.service.IMemberService;
import lombok.extern.slf4j.Slf4j;

/**
* 注解版业务操作类
* @author Tom
*/

@Slf4j
public class MemberService implements IMemberService{

public Member get(String id){
log.info("getMemberById method . . .");
return new Member();
}

public Member get(){
log.info("getMember method . . .");
return new Member();
}

public void save(Member member){
log.info("save member method . . .");
}

public Boolean delete(String id) throws Exception{
log.info("delete method . . .");
throw new Exception("spring aop ThrowAdvice演示");
}
}

LogAspect切面增强类

package com.gupaoedu.springaop.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("出现异常");
   }
}

仿写JDK动态代理

GPInvocationHandler JDK动态代理接口

package com.gupaoedu.springaop.framework.proxy;

import java.lang.reflect.Method;

/**
* Created by Tom.
*/

public interface GPInvocationHandler {
   Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

GPClassLoader自定义类加载器

package com.gupaoedu.springaop.framework.proxy;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

/**
* Created by Tom.
*/

public class GPClassLoader extends ClassLoader {

   private File classPathFile;
   public GPClassLoader(){
       String classPath = GPClassLoader.class.getResource("").getPath();
       this.classPathFile = new File(classPath);
   }

   @Override
   protected Class<?> findClass(String name) throws ClassNotFoundException {

       String className = GPClassLoader.class.getPackage().getName() + "." + name;
       if(classPathFile  != null){
           File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
           if(classFile.exists()){
               FileInputStream in = null;
               ByteArrayOutputStream out = null;
               try{
                   in = new FileInputStream(classFile);
                   out = new ByteArrayOutputStream();
                   byte [] buff = new byte[1024];
                   int len;
                   while ((len = in.read(buff)) != -1){
                       out.write(buff,0,len);
                   }
                   return defineClass(className,out.toByteArray(),0,out.size());
               }catch (Exception e){
                   e.printStackTrace();
               }
           }
       }
       return null;
   }
}

GPProxy 动态生成代理类

package com.gupaoedu.springaop.framework.proxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
* 用来生成源代码的工具类
* Created by Tom.
*/

public class GPProxy {

   public static final String ln = "\r\n";

   public static Object newProxyInstance(GPClassLoader classLoader, Class<?> [] interfaces, GPInvocationHandler h){
      try {
          //1、动态生成源代码.java文件
          String src = generateSrc(interfaces);

          //2、Java文件输出磁盘
          String filePath = GPProxy.class.getResource("").getPath();
//           System.out.println(filePath);
          File f = new File(filePath + "$Proxy0.java");
          FileWriter fw = new FileWriter(f);
          fw.write(src);
          fw.flush();
          fw.close();

          //3、把生成的.java文件编译成.class文件
          JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
          StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
          Iterable iterable = manage.getJavaFileObjects(f);

          JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
          task.call();
          manage.close();

          //4、编译生成的.class文件加载到JVM中来
          Class proxyClass =  classLoader.findClass("$Proxy0");
          Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
          f.delete();

           //5、返回字节码重组以后的新的代理对象
           return c.newInstance(h);
      }catch (Exception e){
          e.printStackTrace();
      }
       return null;
   }

   private static String generateSrc(Class<?>[] interfaces){
           StringBuffer sb = new StringBuffer();
           sb.append("package com.gupaoedu.springaop.framework.proxy;" + ln);
           sb.append("import java.lang.reflect.*;" + ln);
           sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
               sb.append("GPInvocationHandler h;" + ln);
               sb.append("public $Proxy0(GPInvocationHandler h) { " + ln);
                   sb.append("this.h = h;");
               sb.append("}" + ln);
               for (Method m : interfaces[0].getMethods()){
                   Class<?>[] params = m.getParameterTypes();

                   StringBuffer paramNames = new StringBuffer();
                   StringBuffer paramValues = new StringBuffer();
                   StringBuffer paramTypes = new StringBuffer();

                   for (int i = 0; i < params.length; i++) {
                       Class clazz = params[i];
                       String type = clazz.getName();
                       String paramName = toLowerFirstCase(clazz.getSimpleName());
                       paramNames.append(type + " " +  paramName);
                       paramValues.append(paramName);
                       paramTypes.append(clazz.getName() + ".class");
                       if(i > 0 && i < params.length-1){
                           paramNames.append(",");
                           paramTypes.append(",");
                           paramValues.append(",");
                       }
                   }

                   sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames.toString() + ") {" + ln);
                       sb.append("try{" + ln);
                           sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramTypes.toString() + "});" + ln);
                           sb.append((hasReturnValue(m.getReturnType()) ? "return (" + m.getReturnType().getName() + ")" : "") + getCaseCode("this.h.invoke(this,m,new Object[]{" + paramValues + "})",m.getReturnType()) + ";" + ln);
                       sb.append("}catch(Error _ex) { }");
                       sb.append("catch(Throwable e){" + ln);
                       sb.append("throw new UndeclaredThrowableException(e);" + ln);
                       sb.append("}");
                       sb.append(getReturnEmptyCode(m.getReturnType()));
                   sb.append("}");
               }
           sb.append("}" + ln);
           return sb.toString();
   }


   private static Map<Class,Class> mappings = new HashMap<Class, Class>();
   static {
       mappings.put(int.class,Integer.class);
   }

   private static String getReturnEmptyCode(Class<?> returnClass){
       if(mappings.containsKey(returnClass)){
           return "return 0;";
       }else if(returnClass == void.class){
           return "";
       }else {
           return "return null;";
       }
   }

   private static String getCaseCode(String code,Class<?> returnClass){
       if(mappings.containsKey(returnClass)){
           return "((" + mappings.get(returnClass).getName() +  ")" + code + ")." + returnClass.getSimpleName() + "Value()";
       }
       return code;
   }

   private static boolean hasReturnValue(Class<?> clazz){
       return clazz != void.class;
   }

   private static String toLowerFirstCase(String src){
       char [] chars = src.toCharArray();
       chars[0] += 32;
       return String.valueOf(chars);
   }

}


手写Spring AOP

GPAopConfig 保存配置信息

package com.gupaoedu.springaop.framework.config;

import lombok.Data;

/**
* Created by Tom.
*/

@Data
public class GPAopConfig {

   private String pointCut;
   private String aspectBefore;
   private String aspectAfter;
   private String aspectClass;
   private String aspectAfterThrow;
   private String aspectAfterThrowingName;

}

GPAdvice通知接口

package com.gupaoedu.springaop.framework.aspect;

import java.lang.reflect.Method;

/**
* 用于通知回调
*/

public class GPAdvice {
   private Object aspect;
   private Method adviceMethod;
   private String throwName;

   public GPAdvice(Object aspect, Method adviceMethod) {
       this.aspect = aspect;
       this.adviceMethod = adviceMethod;
   }

   public Object getAspect() {
       return aspect;
   }

   public Method getAdviceMethod() {
       return adviceMethod;
   }

   public void setThrowName(String throwName) {
       this.throwName = throwName;
   }

   public String getThrowName() {
       return throwName;
   }
}

GPJoinPoint切点

package com.gupaoedu.springaop.framework.aspect;

import java.lang.reflect.Method;


public interface GPJoinPoint {

   Object getThis();

   Object[] getArguments();

   Method getMethod();

   void setUserAttribute(String key, Object value);

   Object getUserAttribute(String key);
}

GPAdvisedSupport 解析切面配置

package com.gupaoedu.springaop.framework.aop;

import com.gupaoedu.springaop.framework.aspect.GPAdvice;
import com.gupaoedu.springaop.framework.config.GPAopConfig;
import com.gupaoedu.springaop.framework.proxy.GPClassLoader;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Created by Tom.
*/

public class GPAdvisedSupport {

   private GPClassLoader classLoader;

   private Class<?> targetClass;

   private Object target;

   private GPAopConfig config;

   private Pattern pointCutClassPattern;

   private transient Map<Method, Map<String,GPAdvice>> methodCache;

   public GPAdvisedSupport(GPAopConfig config) {
       this.config = config;
       this.classLoader = new GPClassLoader();
   }

   public Class<?> getTargetClass(){
       return this.targetClass;
   }

   public Object getTarget(){
       return this.target;
   }

   public Map<String,GPAdvice> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) throws Exception{
       Map<String,GPAdvice> 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 void setTargetClass(Class<?> targetClass) {
       this.targetClass = targetClass;
       parse();
   }

   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, Map<String,GPAdvice>>();
           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()){
                   //执行器链
                   Map<String,GPAdvice> advices = new HashMap<String, GPAdvice>();
                   //把每一个方法包装成 MethodIterceptor
                   //before
                   if(!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) {
                       //创建一个Advivce
                       advices.put("before",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectBefore())));
                   }
                   //after
                   if(!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) {
                       //创建一个Advivce
                       advices.put("after",new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfter())));
                   }
                   //afterThrowing
                   if(!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))) {
                       //创建一个Advivce
                       GPAdvice throwingAdvice = new GPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfterThrow()));
                       throwingAdvice.setThrowName(config.getAspectAfterThrowingName());
                       advices.put("afterThrow",throwingAdvice);
                   }
                   methodCache.put(m,advices);
               }

           }
       }catch (Exception e){
           e.printStackTrace();
       }


   }

   public void setTarget(Object target) {
       this.target = target;
   }

   public boolean pointCutMatch() {
       return pointCutClassPattern.matcher(this.targetClass.toString()).matches();
   }

   public GPClassLoader getClassLoader() { return classLoader; }
}


GPJdkDynamicAopProxy实现动态代理

package com.gupaoedu.springaop.framework.aop;

import com.gupaoedu.springaop.framework.aspect.GPAdvice;
import com.gupaoedu.springaop.framework.proxy.GPClassLoader;
import com.gupaoedu.springaop.framework.proxy.GPInvocationHandler;
import com.gupaoedu.springaop.framework.proxy.GPProxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.util.Map;

/**
* Created by Tom.
*/

public class GPJdkDynamicAopProxy implements GPInvocationHandler {

   private GPAdvisedSupport advised;

   public GPJdkDynamicAopProxy(GPAdvisedSupport config){
       this.advised = config;
   }

   public Object getProxy() {
       return getProxy(this.advised.getClassLoader());
   }


   public Object getProxy(GPClassLoader classLoader) {
       return GPProxy.newProxyInstance(classLoader,this.advised.getTargetClass().getInterfaces(),this);
   }


   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Map<String,GPAdvice> advices = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,this.advised.getTargetClass());
       invokeAdvice(advices.get("before"));
       Object returnValue = null;
       try {
           returnValue = method.invoke(this.advised.getTarget(), args);
       }catch (Exception e){
           invokeAdvice(advices.get("afterThrow"));
       }
       invokeAdvice(advices.get("after"));
       return returnValue;
   }

   private void invokeAdvice(GPAdvice advice){
       try {
           advice.getAdviceMethod().invoke(advice.getAspect());
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (InvocationTargetException e) {
           e.printStackTrace();
       }
   }
}

测试代码

MemberServiceTest测试用例

package com.gupaoedu.springaop.service;

import com.gupaoedu.springaop.demo.service.IMemberService;
import com.gupaoedu.springaop.framework.GPApplicationContext;

public class MemberServiceTest {
   
   public static void main(String[] args) {
       GPApplicationContext applicationContext = new GPApplicationContext();
       IMemberService memberService = (IMemberService)applicationContext.getBean("memberService");
       try {
           memberService.delete("1");
       } catch (Exception e) {
           e.printStackTrace();
       }

   }

}

运行结果


java培训班


java培训班:http://www.baizhiedu.com/java2019


上一篇:java架构师 | 设计模式概述:设计模式从何而来?

下一篇:应届生去公司找个Java程序员的职位需要什么技能?

相关推荐

www.baizhiedu.com

有位老师想和您聊一聊

关闭

立即申请