美文网首页程序员
SpringAOP那些无处不在的动态代理

SpringAOP那些无处不在的动态代理

作者: Java架构 | 来源:发表于2019-10-22 09:42 被阅读0次

环境配置

代码结构

pom.xml文件

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.gupaoedu

gupaoedu-springaop

0.0.1-SNAPSHOT

gupaoedu-springaop

1.8

org.projectlombok

lombok

1.16.10

org.slf4j

slf4j-api

1.7.25

ch.qos.logback

logback-classic

1.2.3

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实体类

packagecom.gupaoedu.springaop.demo.model;

publicclassMember{

}

IMermverServer接口

packagecom.gupaoedu.springaop.demo.service;

importcom.gupaoedu.springaop.demo.model.Member;

/**

* 注解版业务操作类

*@authorTom

*/

publicinterfaceIMemberService{

publicMemberget(String id);

publicMemberget();

publicvoidsave(Member member);

publicBooleandelete(String id)throwsException;

}

MemberService业务实现类

packagecom.gupaoedu.springaop.demo.service.impl;

importcom.gupaoedu.springaop.demo.model.Member;

importcom.gupaoedu.springaop.demo.service.IMemberService;

importlombok.extern.slf4j.Slf4j;

/**

* 注解版业务操作类

*@authorTom

*/

@Slf4j

publicclassMemberServiceimplementsIMemberService{

publicMemberget(String id){

log.info("getMemberById method . . .");

returnnewMember();

}

publicMemberget(){

log.info("getMember method . . .");

returnnewMember();

}

publicvoidsave(Member member){

log.info("save member method . . .");

}

publicBooleandelete(String id)throwsException{

log.info("delete method . . .");

thrownewException("spring aop ThrowAdvice演示");

}

}

LogAspect切面增强类

packagecom.gupaoedu.springaop.demo.aspect;

importlombok.extern.slf4j.Slf4j;

/**

* Created by Tom.

*/

@Slf4j

publicclassLogAspect{

//在调用一个方法之前,执行before方法

publicvoidbefore(){

//这个方法中的逻辑,是由我们自己写的

log.info("Invoker Before Method!!!");

}

//在调用一个方法之后,执行after方法

publicvoidafter(){

log.info("Invoker After Method!!!");

}

publicvoidafterThrowing(){

log.info("出现异常");

}

}

仿写JDK动态代理

GPInvocationHandler JDK动态代理接口

packagecom.gupaoedu.springaop.framework.proxy;

importjava.lang.reflect.Method;

/**

* Created by Tom.

*/

publicinterfaceGPInvocationHandler{

Objectinvoke(Object proxy, Method method, Object[] args)throwsThrowable;

}

GPClassLoader自定义类加载器

packagecom.gupaoedu.springaop.framework.proxy;

importjava.io.ByteArrayOutputStream;

importjava.io.File;

importjava.io.FileInputStream;

/**

* Created by Tom.

*/

publicclassGPClassLoaderextendsClassLoader{

privateFile classPathFile;

publicGPClassLoader(){

String classPath = GPClassLoader.class.getResource("").getPath();

this.classPathFile =newFile(classPath);

}

@Override

protectedClass findClass(String name)throwsClassNotFoundException {

String className = GPClassLoader.class.getPackage().getName() +"."+ name;

if(classPathFile  !=null){

File classFile =newFile(classPathFile,name.replaceAll("\\.","/") +".class");

if(classFile.exists()){

FileInputStream in =null;

ByteArrayOutputStream out =null;

try{

in =newFileInputStream(classFile);

out =newByteArrayOutputStream();

byte[] buff =newbyte[1024];

intlen;

while((len = in.read(buff)) != -1){

out.write(buff,0,len);

}

returndefineClass(className,out.toByteArray(),0,out.size());

}catch(Exception e){

e.printStackTrace();

}

}

}

returnnull;

}

}

GPProxy 动态生成代理类

packagecom.gupaoedu.springaop.framework.proxy;

importjavax.tools.JavaCompiler;

importjavax.tools.StandardJavaFileManager;

importjavax.tools.ToolProvider;

importjava.io.File;

importjava.io.FileWriter;

importjava.lang.reflect.Constructor;

importjava.lang.reflect.Method;

importjava.util.HashMap;

importjava.util.Map;

/**

* 用来生成源代码的工具类

* Created by Tom.

*/

publicclassGPProxy{

publicstaticfinalString ln ="\r\n";

publicstaticObjectnewProxyInstance(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 =newFile(filePath +"$Proxy0.java");

FileWriter fw =newFileWriter(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、返回字节码重组以后的新的代理对象

returnc.newInstance(h);

}catch(Exception e){

e.printStackTrace();

}

returnnull;

}

privatestaticStringgenerateSrc(Class<?>[] interfaces){

StringBuffer sb =newStringBuffer();

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 =newStringBuffer();

StringBuffer paramValues =newStringBuffer();

StringBuffer paramTypes =newStringBuffer();

for(inti =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);

returnsb.toString();

}

privatestaticMap mappings =newHashMap();

static{

mappings.put(int.class,Integer.class);

}

privatestaticStringgetReturnEmptyCode(Class<?> returnClass){

if(mappings.containsKey(returnClass)){

return"return 0;";

}elseif(returnClass ==void.class){

return"";

}else{

return"return null;";

}

}

privatestaticStringgetCaseCode(String code,Class<?> returnClass){

if(mappings.containsKey(returnClass)){

return"(("+ mappings.get(returnClass).getName() +")"+ code +")."+ returnClass.getSimpleName() +"Value()";

}

returncode;

}

privatestaticbooleanhasReturnValue(Class<?> clazz){

returnclazz !=void.class;

}

privatestaticStringtoLowerFirstCase(String src){

char[] chars = src.toCharArray();

chars[0] +=32;

returnString.valueOf(chars);

}

}

手写Spring AOP

GPAopConfig 保存配置信息

packagecom.gupaoedu.springaop.framework.config;

importlombok.Data;

/**

* Created by Tom.

*/

@Data

publicclassGPAopConfig{

privateString pointCut;

privateString aspectBefore;

privateString aspectAfter;

privateString aspectClass;

privateString aspectAfterThrow;

privateString aspectAfterThrowingName;

}

GPAdvice通知接口

packagecom.gupaoedu.springaop.framework.aspect;

importjava.lang.reflect.Method;

/**

* 用于通知回调

*/

publicclassGPAdvice{

privateObject aspect;

privateMethod adviceMethod;

privateString throwName;

publicGPAdvice(Object aspect, Method adviceMethod){

this.aspect = aspect;

this.adviceMethod = adviceMethod;

}

publicObjectgetAspect(){

returnaspect;

}

publicMethodgetAdviceMethod(){

returnadviceMethod;

}

publicvoidsetThrowName(String throwName){

this.throwName = throwName;

}

publicStringgetThrowName(){

returnthrowName;

}

}

GPJoinPoint切点

packagecom.gupaoedu.springaop.framework.aspect;

importjava.lang.reflect.Method;

publicinterfaceGPJoinPoint{

ObjectgetThis();

Object[] getArguments();

MethodgetMethod();

voidsetUserAttribute(String key, Object value);

ObjectgetUserAttribute(String key);

}

GPAdvisedSupport 解析切面配置

packagecom.gupaoedu.springaop.framework.aop;

importcom.gupaoedu.springaop.framework.aspect.GPAdvice;

importcom.gupaoedu.springaop.framework.config.GPAopConfig;

importcom.gupaoedu.springaop.framework.proxy.GPClassLoader;

importjava.lang.reflect.Method;

importjava.util.HashMap;

importjava.util.Map;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

/**

* Created by Tom.

*/

publicclassGPAdvisedSupport{

privateGPClassLoader classLoader;

privateClass targetClass;

privateObject target;

privateGPAopConfig config;

privatePattern pointCutClassPattern;

privatetransientMap> methodCache;

publicGPAdvisedSupport(GPAopConfig config){

this.config = config;

this.classLoader =newGPClassLoader();

}

publicClass getTargetClass(){

returnthis.targetClass;

}

publicObjectgetTarget(){

returnthis.target;

}

publicMapgetInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass)throwsException{

Map cached = methodCache.get(method);

if(cached ==null){

Method m = targetClass.getMethod(method.getName(),method.getParameterTypes());

cached = methodCache.get(m);

//底层逻辑,对代理方法进行一个兼容处理

this.methodCache.put(m,cached);

}

returncached;

}

publicvoidsetTargetClass(Class<?> targetClass){

this.targetClass = targetClass;

parse();

}

privatevoidparse(){

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 =newHashMap>();

Pattern pattern = Pattern.compile(pointCut);

Class aspectClass = Class.forName(this.config.getAspectClass());

Map aspectMethods =newHashMap();

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 advices =newHashMap();

//把每一个方法包装成 MethodIterceptor

//before

if(!(null== config.getAspectBefore() ||"".equals(config.getAspectBefore()))) {

//创建一个Advivce

advices.put("before",newGPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectBefore())));

}

//after

if(!(null== config.getAspectAfter() ||"".equals(config.getAspectAfter()))) {

//创建一个Advivce

advices.put("after",newGPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfter())));

}

//afterThrowing

if(!(null== config.getAspectAfterThrow() ||"".equals(config.getAspectAfterThrow()))) {

//创建一个Advivce

GPAdvice throwingAdvice =newGPAdvice(aspectClass.newInstance(),aspectMethods.get(config.getAspectAfterThrow()));

throwingAdvice.setThrowName(config.getAspectAfterThrowingName());

advices.put("afterThrow",throwingAdvice);

}

methodCache.put(m,advices);

}

}

}catch(Exception e){

e.printStackTrace();

}

}

publicvoidsetTarget(Object target){

this.target = target;

}

publicbooleanpointCutMatch(){

returnpointCutClassPattern.matcher(this.targetClass.toString()).matches();

}

publicGPClassLoadergetClassLoader(){returnclassLoader; }

}

GPJdkDynamicAopProxy实现动态代理

packagecom.gupaoedu.springaop.framework.aop;

importcom.gupaoedu.springaop.framework.aspect.GPAdvice;

importcom.gupaoedu.springaop.framework.proxy.GPClassLoader;

importcom.gupaoedu.springaop.framework.proxy.GPInvocationHandler;

importcom.gupaoedu.springaop.framework.proxy.GPProxy;

importjava.lang.reflect.InvocationTargetException;

importjava.lang.reflect.Method;

importjava.util.Map;

/**

* Created by Tom.

*/

publicclassGPJdkDynamicAopProxyimplementsGPInvocationHandler{

privateGPAdvisedSupport advised;

publicGPJdkDynamicAopProxy(GPAdvisedSupport config){

this.advised = config;

}

publicObjectgetProxy(){

returngetProxy(this.advised.getClassLoader());

}

publicObjectgetProxy(GPClassLoader classLoader){

returnGPProxy.newProxyInstance(classLoader,this.advised.getTargetClass().getInterfaces(),this);

}

publicObjectinvoke(Object proxy, Method method, Object[] args)throwsThrowable{

Map 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"));

returnreturnValue;

}

privatevoidinvokeAdvice(GPAdvice advice){

try{

advice.getAdviceMethod().invoke(advice.getAspect());

}catch(IllegalAccessException e) {

e.printStackTrace();

}catch(InvocationTargetException e) {

e.printStackTrace();

}

}

}

测试代码

MemberServiceTest测试用例

packagecom.gupaoedu.springaop.service;

importcom.gupaoedu.springaop.demo.service.IMemberService;

importcom.gupaoedu.springaop.framework.GPApplicationContext;

publicclassMemberServiceTest{

publicstaticvoidmain(String[] args){

GPApplicationContext applicationContext =newGPApplicationContext();

IMemberService memberService = (IMemberService)applicationContext.getBean("memberService");

try{

memberService.delete("1");

}catch(Exception e) {

e.printStackTrace();

}

}

}

运行结果

相关文章

  • Spring AOP 一

    上一篇讲了jdk动态代理,下面我们来说说SpringAOP。SpringAOP是基于动态代理的,它对动态代理又做了...

  • 面试系列~动态代理实现与原理

    动态代理有JDK动态代理, CGLIB动态代理, SpringAOP动态代理 一,JDK动态代理  jdk动态代理...

  • SpringAOP那些无处不在的动态代理

    环境配置 代码结构 pom.xml文件 xsi:schemaLocation="http://maven.apac...

  • JVM_字节码:字节码层面看看动态代理

    SpringAop是基于动态代理的,主要有2种方式:JDK的动态代理,CGLIB的代理,增加织入的功能。 JDK动...

  • Spring学习(五)AOP

    SpringAop使用到了了动态代理模式(有关设计模式见设计模式章节)。JDK动态代理代理的目标类必须要实现接口。...

  • SpringAOP-jdk动态代理

    静态代理与动态代理 静态代理(如SpringAOP-代理模式中所示)的缺点代理目标的方法越多,代理所委托的方法就越...

  • Spring_AOP_02——实现原理

    本文主要讲实现AOP的 代理模式原理,以及静态代理,动态代理的区别和具体实现。 对SpringAOP的概念和使用,...

  • SpringAOP

    springAOP实现方式 1.动态代理 使用 Proxy机制,使用反射技术,创建实际对象的代理对象,添加AOP的...

  • 代理模式

    代理模式的典型就是springAOP代理模式的目的有两个:保护目标对象,增强目标对象分类:静态代理和动态代理。 静...

  • SpringAOP以及动态代理

    AOP,即面向切面编程,算是OOP(面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次...

网友评论

    本文标题:SpringAOP那些无处不在的动态代理

    本文链接:https://www.haomeiwen.com/subject/rgfgpctx.html