Realization of JDK dynamic proxy in Spring AOP
Dynamic proxy mechanism
-
Create your own invocation handler by implementing the InvocationHandler interface
-
Create a dynamic proxy class by specifying a ClassLoader object and a set of interfaces for the Proxy class
-
The constructor of the dynamic proxy class is obtained through the reflection mechanism, and the only parameter type is the call processor interface type
-
The dynamic proxy class instance is created through the constructor, and the processor object is called as a parameter during construction.
AOP thinking
-
OOP introduces concepts such as encapsulation, inheritance, and polymorphism to establish a hierarchy of objects to simulate a collection of public behaviors.
-
The AOP technology uses a technique called "cross-cutting" to dissect the inside of the encapsulated object and encapsulate those common behaviors that affect multiple classes into a reusable module, which can reduce the duplication of the system code and reduce the inter-module The degree of coupling is conducive to future operability and maintainability.
-
AOP divides the software system into two parts: core concerns and cross-cutting concerns. The main process of business processing is the core concern, and the part that has little to do with it is the cross-cutting concern.
Dynamic proxy source code to implement AopProxyFactory
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
// 表示在有接口实现的时候采用JDK动态代理
return new JdkDynamicAopProxy(config);
}
// 在没有接口实现的时候采用Cglib动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
Implementation of AOP in Spring
The program is executed from top to bottom, and has little relationship with the main business logic. AOP aspect-oriented programming is to separate the main business from the cross-cutting code and achieve decoupling.
Common implementations are:
- Unified log processing
- Unified exception handling
- Spring transaction management
Code
Define the interface
/**
* @ClassName: BuyService
* @Description: 购买基础接口
* @Author: 尚先生
* @CreateDate: 2019/6/17 14:52
* @Version: 1.0
*/
public interface BuyService {
String buyPhone(BuyService buyService);
String buyComputer(BuyService buyService);
}
Define the implementation class
/**
* @ClassName: BusiServiceImpl
* @Description: 购买实现类
* @Author: 尚先生
* @CreateDate: 2019/6/17 14:53
* @Version: 1.0
*/
@Service
public class BuyServiceImpl implements BuyService {
@Intercept("buyPhone")
@Override
public String buyPhone(BuyService buyService) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("==========当前类描述 " + buyService.getClass().getName() + "=============" + " buyPhone");
this.buyComputer(this);
return "buy phone";
}
@Intercept("buyComputer")
@Override
public String buyComputer(BuyService buyService) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("==========当前类描述 " + buyService.getClass().getName() + "=============" + " buyComputer");
return "buy computer";
}
}
Custom block annotation
/**
* @ClassName: Intercept
* @Description: 自定义拦截器注解
* @Author: 尚先生
* @CreateDate: 2019/6/17 16:28
* @Version: 1.0
*/
@Target({
ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Intercept {
String value() default "";
}
Custom interceptor implementation
/**
* @ClassName: Interceptor
* @Description: 拦截器实现类
* @Author: 尚先生
* @CreateDate: 2019/6/17 15:12
* @Version: 1.0
*/
@Component
@Aspect
public class Interceptor {
@Pointcut(value = "@annotation(com.learn.demo.java.proxy.Intercept)")
public void buySomething() {
System.out.println("===========自定义切入点===============");
}
@Around("buySomething()")
public Object around(ProceedingJoinPoint point) throws Throwable {
try {
//通过获取 Intercept 注解
Method proxyMethod = ((MethodSignature) point.getSignature()).getMethod();
Method targetMethod = point.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
Intercept intercept = targetMethod.getAnnotation(Intercept.class);
String methodName = targetMethod.getName();
//处理注解逻辑
String value = intercept.value();
System.err.println("=========== " + methodName + " 获取前置拦截信息 ===========" + value);
return point.proceed();
} catch (Throwable e) {
System.out.println("执行异常"+ e.getMessage());
}finally {
System.err.println("=========== " + " 后置处理结果返回 ===========");
}
return "执行异常,请查看详细日志信息";
}
}
Custom interceptor configuration class
/**
* @ClassName: AspectJConfig
* @Description: 开启Spring对AspectJ的支持
* @Author: 尚先生
* @CreateDate: 2019/6/17 18:39
* @Version: 1.0
*/
@Configuration
@ComponentScan("com.learn.demo.java.proxy")
@EnableAspectJAutoProxy
public class AspectJConfiguration {
}
Start the boot class
/**
* @ClassName: Bootstrap
* @Description: 启动测试类
* @Author: 尚先生
* @CreateDate: 2019/6/17 14:58
* @Version: 1.0
*/
public class Bootstrap {
public static void main(String[] args) {
// spring 采用的 jdk 动态代理
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.learn.demo.java.proxy");
context.register(Interceptor.class);
context.refresh();
BuyService bean = context.getBean("buyServiceImpl", BuyService.class);
String phone = bean.buyPhone(bean);
System.err.println("=========Bootstrap.class============== " + phone);
// 输出代理对象 class 文件
createProxyClassFile();
}
/**
* 生成代理文件
*/
private static void createProxyClassFile() {
String name = "ProxyBuyService";
byte[] data = ProxyGenerator.generateProxyClass(name,
new Class[] {
BuyService.class});
FileOutputStream out = null;
try {
out = new FileOutputStream("D://" + name + ".class");
out.write(data);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != out)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Results of the
=========== buyPhone 获取前置拦截信息 ===========buyPhone
==========当前类描述 com.sun.proxy.$Proxy22============= buyPhone
=========== 后置处理结果返回 ===========
=========Bootstrap.class============== buy phone
==========当前类描述 com.learn.demo.java.proxy.BuyServiceImpl============= buyComputer
Process analysis
-
From the execution results, you can clearly see the object com.sun.proxy.$Proxy22 executed in buyPhone(), and then execute this.buyComputer(this); the executed object becomes com.learn.demo.java.proxy.BuyServiceImpl , So only the buyPhone() method will be intercepted in aspect-oriented programming.
-
The main reason is that the generated proxy object is not the same as the proxy object, so the latter calls the class method as if it is a direct call, without going across the board.
-
The code has been updated in GitHub . For more details, please follow dwyanewede . For more JDK dynamic proxy, please refer to the previous article: JDK dynamic proxy implementation principle
More excellent articles
JDK dynamic proxy implementation principle
https://blog.csdn.net/shang_xs/article/details/92772437
Primary school students in java
https://blog.csdn.net/shang_xs