本篇是介绍java实现代理对象的两种方法,JDK动态代理和CGLIB。
JDK动态代理:针对你所调用的方法是接口所定义的方法。动态的创建一个类,通过实现目标类的接口来实现代理。
CGLIB:没有限制。通过继承目标类来创建代理类,实现代理。
下面看案例:
案例一,JDK动态代理:
Person和Animals都实现了Say接口sayHello方法。现在就需要对他们的sayHello方法进行拦截。
Say接口如下:
public interface Say {
public void sayHello();
}
Person类如下:
package com.lg.aop.base;
public class Person implements Say{
private String name;
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
@Override
public void sayHello() {
System.out.println("My name is "+name+"!");
throw new RuntimeException();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Animal类如下:
public class Animals implements Say{
@Override
public void sayHello() {
System.out.println("I am a animal");
}
}
使用JDK动态代理来创建代理对象的工具类JDKDynamicProxy如下:
package com.lg.aop.base;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKDynamicProxy {
public static Object createProxy(final Object target){
return Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getName().equals("sayHello")){
doBefore();
try {
method.invoke(target, args);
} catch (Exception e) {
doThrowing();
}
doAfter();
}
return null;
}
});
}
private static void doThrowing() {
System.out.println("AOP say throw a exception");
}
private static void doBefore() {
System.out.println("AOP before say");
}
private static void doAfter() {
System.out.println("AOP after say");
}
}
JDK动态代理就是通过Proxy.newProxyInstance来创建代理对象的:
第一个参数是ClassLoader:因为此次代理会创建一个Say接口的实现类,需要将这个类加载到jvm中,所以用到了ClassLoader。
第二个参数是代理类要实现的所有接口:当你调用这些接口的方法时都会进行拦截。
第三个参数是InvocationHandler,每次调用代理对象的方法时,都会先执行InvocationHandler的invoke方法,在该方法中实现我们的拦截逻辑。
在本案例中,InvocationHandler的invoke方法中,我们的拦截逻辑是这样的,当调用sayHello方法时,进行doBefore、doAfter、doThrowing等拦截。
测试类如下:
package com.lg.aop.base;
public class ProxyTest {
public static void main(String[] args){
Say say1=new Person("lg");
say1=(Say)JDKDynamicProxy.createProxy(say1);
say1.sayHello();
System.out.println("-------------------------------");
Say say2=new Animals();
say2=(Say) JDKDynamicProxy.createProxy(say2);
say2.sayHello();
}
}
测试结果如下:
AOP before say
My name is lg!
AOP say throw a exception
AOP after say
-------------------------------
AOP before say
I am a animal
AOP after say
我们可以看到实现了相应的拦截。
这里说明下几个概念,
(1)Proxy.newProxyInstance的返回结果和目标对象Person实现了同样的接口,但他们之间不能相互转化。即say1=(Person)JDKDynamicProxy.createProxy(say1);是错误的。
(2)InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法中的Object proxy是Proxy.newProxyInstance的返回的代理对象,不是目标对象Person,因此希望执行原目标对象的sayHello方法时,method.invoke(target, args);所传对象是原目标对象,而不是代理对象proxy。
这就是JDK动态代理的原理,目前这些拦截都是硬编码写死的,如果我们继续进一步改造,便也可以实现更加灵活的代理,有兴趣的可以实现自己的AOP。
案例二,CGLIB代理:
首先在pom文件中引入cglib库。如下:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
还是针对同样的Person、Animals、Say接口。只是这次创建代理对象的方式变了,如下:
package com.lg.aop.base;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
public class CglibProxy {
@SuppressWarnings("unchecked")
public static <T> T createProxy(final T t){
Enhancer enhancer=new Enhancer();
enhancer.setClassLoader(CglibProxy.class.getClassLoader());
enhancer.setSuperclass(t.getClass());
enhancer.setCallback(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object ret=null;
if(method.getName().equals("sayHello")){
doBefore();
try {
ret=method.invoke(t, args);
} catch (Exception e) {
doThrowing();
}
doAfter();
}
return ret;
}
});
return (T)enhancer.create();
}
private static void doThrowing() {
System.out.println("AOP say throw a exception");
}
private static void doBefore() {
System.out.println("AOP before say");
}
private static void doAfter() {
System.out.println("AOP after say");
}
}
使用cglib的Enhancer来创建,创建出的代理对象继承了指定的class。
(1)enhancer.setClassLoader:也是指定类加载器,将创建出来的新类加载到jvm中。
(2)enhancer.setSuperclass(t.getClass()):设置目标类作为代理对象的父类。
(3)enhancer.setCallback:设置一个回调函数,每次调用代理类的方法时,先执行该回调函数。
然后就是测试:
public class ProxyTest {
public static void main(String[] args){
cglibTest();
}
public static void cglibTest(){
Person p=new Person("lg");
p=CglibProxy.createProxy(p);
p.sayHello();
System.out.println("-------------------------------");
Animals animals=new Animals();
animals=CglibProxy.createProxy(animals);
animals.sayHello();
}
}
p=CglibProxy.createProxy(p):由于创建出来的代理对象就是目标对象的子类,所以不用像JDK动态代理那样创建出的代理类只能是Say类型。
运行效果如下:
AOP before say
My name is lg!
AOP say throw a exception
AOP after say
-------------------------------
AOP before say
I am a animal
AOP after say
和JDK动态代理一样的效果,实现了拦截。
总结一下:
(1)当你所调用的目标对象的方法是接口所定义的方法时,可以使用JDK动态代理或者Cglib。即当你的目标类虽然实现了接口,但是所调用的方法却不是接口方法时,就无法使用JDK动态代理,因为JDK动态代理的原理就是实现和目标对象同样的接口,因此只能调用那些接口方法。
(2)Cglib则没有此限制,因为它所创建出来的代理对象就是目标类的子类,因此可以调用目标类的任何方法(除去final方法,final方法不可继承),都会进行拦截。
所以SpringAOP会优先选择JDK动态代理,当调用方法不是接口方法时,只能选择Cglib了。
分享到:
相关推荐
Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...
在"通过Configuration文件实现AOP.docx"文档中,可能会详细讲述如何在Spring配置文件中配置AOP代理,包括如何选择使用JDK动态代理还是CGLIB。 总结来说,JDK动态代理简单且高效,适合接口驱动的设计,而CGLIB适用于...
Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...
在实际开发中,如Spring AOP框架就同时支持JDK和CGLIB动态代理,根据目标类是否实现接口自动选择合适的代理方式。 总结来说,JDK动态代理和CGLIB动态代理都是为了在运行时提供对目标对象的增强,它们通过不同的实现...
在Java编程领域,Spring框架是应用最广泛的轻量级开源框架之一,它提供了一系列强大的功能,包括依赖注入、面向切面编程(AOP)...在实际项目中,熟练掌握Spring AOP和JDK动态代理,能够有效地提升开发效率和软件质量。
在Spring中,AOP主要通过两种动态代理技术实现:JDK动态代理和CGLIB动态代理。 首先,让我们详细了解一下JDK动态代理。JDK动态代理基于Java的接口实现,它适用于目标对象实现了至少一个接口的情况。在运行时,JDK...
现在让我们深入探讨JDK动态代理和Spring AOP的原理。 首先,JDK动态代理基于Java的反射机制,通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象,...
Spring AOP 中 JDK 和 CGLib 动态代理哪个更快?
在Spring AOP的源码中,`org.springframework.aop.framework.ProxyFactoryBean`是创建代理的主要类,它会根据目标类是否有接口选择JDK动态代理或CGLIB。`org.aopalliance.intercept.MethodInterceptor`接口定义了...
哪怕没有看过源码的同学也应该知道,AOP是通过动态代理实现的,动态代理又分为两个部分:JDK动态代理和CGLIB动态代理 确实,Spring也就是通过这两种方式来实现AOP相关功能,下面就通过源码来简单求证下
Java中的动态代理、反射和...总之,理解和掌握JDK动态代理、CGLIB动态代理、反射和拦截器是提升Java开发技能的关键步骤。通过实际操作这些示例,你将能够更好地应用这些技术到实际项目中,提高代码的灵活性和可维护性。
本文主要介绍 Java 中两种常见的动态代理方式:JDK 原生动态代理和 CGLIB 动态代理。 一、 代理模式 代理模式是指程序通过代理类来访问目标对象,以达到对目标对象的控制和增强。代理模式的优点是可以在不改变目标...
在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态代理。 JDK 动态代理是基于接口的,它要求被代理的目标对象必须实现至少一个接口。Spring 使用 `java.lang.reflect.Proxy`...
Spring支持JDK动态代理和CGLIB动态代理,根据目标类是否实现了接口来选择合适的代理方式。 总结来说,代理模式是软件设计中的一个重要工具,它提供了在不修改原始对象的前提下扩展功能的能力。Java中的静态代理、...
Java提供了两种主要的动态代理实现方式:JDK动态代理和CGLIB动态代理。 **JDK动态代理**: JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。代理机制的核心是`java.lang.reflect.Proxy`类和...
- Spring支持两种类型的代理:JDK动态代理(如果目标对象实现了接口)和CGLIB代理(如果目标对象没有接口,使用字节码生成技术)。 - 在Spring配置中,可以使用`@Aspect`注解定义切面,`@Before`、`@After`、`@...
本资源将深入探讨Spring框架中使用的两种关键的动态代理方式:JDK动态代理和CGLib动态代理。这两种代理方式在Spring AOP中起到关键作用,用于实现横切关注点的切面编程。通过学习它们的原理和实际应用,您将能够更好...
本文将深入探讨Spring AOP中的JDK动态代理机制。 首先,我们要理解什么是动态代理。动态代理是在运行时创建一个实现了一组给定接口的代理类,这个代理类可以拦截并处理方法调用,从而实现一些额外的功能。JDK的动态...
本篇将详细探讨JDK动态代理和Spring AOP,以及它们在实际应用中的作用。 首先,JDK动态代理是Java提供的一种在运行时创建代理对象的技术。它允许我们在不修改原有类的基础上,为已有接口添加额外的功能。动态代理的...
Spring AOP使用两种主要的代理技术:JDK动态代理和CGLIB动态代理。JDK动态代理适用于接口的场景,而CGLIB则用于没有实现接口的情况。在这两种情况下,代理对象都会持有目标对象的引用,并在其上调用方法。具体来说:...