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

环境配置

代码结构

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();
}

}

}

运行结果

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章