`

Spring AOP源码分析(二)JDK动态代理和CGLIB介绍

阅读更多
本篇是介绍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了。
分享到:
评论

相关推荐

    AOP之JDK动态代理和CGLib动态代理

    AOP之JDK动态代理和CGLib动态代理 ,具体效果和过程看博文 http://blog.csdn.net/evankaka/article/details/45195383

    Spring框架中JDK动态代理和cglib动态代理

    Spring框架的AOP中重要的一个知识点,动态代理,springAOP框架会根绝实际情况选择使用jdk的动态代理还是cglib的动态代理

    spring之AOP(动态代理)

    spring之AOP(动态代理),包括jdk动态代理和CGLib动态代理

    Spring AOP源码分析.mmap

    哪怕没有看过源码的同学也应该知道,AOP是通过动态代理实现的,动态代理又分为两个部分:JDK动态代理和CGLIB动态代理 确实,Spring也就是通过这两种方式来实现AOP相关功能,下面就通过源码来简单求证下

    Spring框架+SpringAOP动态代理

    SpringAOP动态代理 Spring AOP 使用的动态代理主要有两种方式:JDK 动态代理和 CGLIB 代理。 JDK 动态代理:用于代理实现了接口的类。Spring 会使用 java.lang.reflect.Proxy 类来创建代理对象。 CGLIB 代理:用于...

    Spring-AOP-JDK动态代理

    Spring-AOP-利用java中的动态代理和Spring的拦截器做到AOP

    SpringAOP的实现机制(底层原理)、应用场景等详解,模拟过程的实例

    本资源将深入探讨Spring框架中使用的两种关键的动态代理方式:JDK动态代理和CGLib动态代理。这两种代理方式在Spring AOP中起到关键作用,用于实现横切关注点的切面编程。通过学习它们的原理和实际应用,您将能够更好...

    Spring aop 之 静态代理 动态代理 Aspectj aop-config 等实现方式

    主要对Spring AOP的相关概念和简单的静态代理、动态代理以及常见的几种AOP配置方式做总结学习。主要包括:1. AOP的常见概念 2. 静态代理 3. jdk动态代理 4. Aspectj and Aspectjweaver 5. **aop-config** 6. CGLIB ...

    spring_aop4.rar_Home Home_jar 转换_spring AOP jar

    3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 如何强制使用CGLIB实现AOP? * 添加CGLIB库,SPRING_HOME/cglib/*.jar * 在spring配置文件中加入&lt;aop:aspectj-...

    cglib aop spring 动态代理

    静态代理--不适合企业开发,适合初学者理解代理。 jdk动态代理--适合企业级开发,但是它要求必须面向接口编程,假如目标类没有实现接口...spring 的AOP功能中 会根据目标类是否实现了接口来判断使用 jdk Proxy还是cglib

    Spring AOP源码深度解析:掌握Java高级编程核心技术

    动态代理是实现AOP的基础,它通过JDK动态代理或CGLIB代理生成被代理对象的子类。通知是织入到目标对象连接点上的一段程序,例如@Before、@After等。 切点定义了通知应该在哪些连接点上触发。而切面则是通知和切点的...

    Spring AOP代理详细介绍

    如果一个类实现了一个或多个接口,那么Spring就会使用默认的JDK动态代理,如果没有实现任何接口,就会使用cglib来代理。当然我们也可以手动改变这些设置。这也是比较容易掉坑的部分,如果设置错了代理方式,那么在...

    Spring框架+Spring工作原理+AOP面向切面编程+JDK代理+Cglib代理

    Spring框架是一个开放源代码的J2EE应用程序框架,是对bean的生命周期进行管理的轻量...Spring框架主要由七部分组成,分别是Spring Core,Spring AOP,Spring ORM,Spring DAO,Spring Context,Spring Web和Spring Web MVC。

    Spring Aop面向切面的java代码

    写了SpringAop的两种代理的实现,jdk动态代理和cglib代理的代码,及测试。

    SpringBoot下的SpringAOP-day04-源代码

    SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法 1.动态代理总结 1.1 JDK动态代理特点 1.2 CGlib动态代理 1.2.1 CGLib特点说明 1.3 动态代理的作用 2 Spring...

    Spring AOP详细介绍.docx

    一 AOP的基本概念 (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知 (2)JointPoint(连接点):程序执行过程中明确的点,...Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

    基于java的企业级应用开发:JDK动态代理.ppt

    对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。 Hibernate 的 二级缓存 学习案例 案例代码 接下来,就通过一个案例来演示Spring中JDK动态代理的实现过程,具体代码请参见教材3.2.1小节。 CGLIB代理 ...

    springAop的配置实现

    SpringAop面向切面编程

    Spring AOP与动态代理

    AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或...Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的

    JAVA的反射机制与动态代理.pdf

    本文档先讲解了JDK的反射机制,然后是Proxy的动态代理、CGLIB的动态代理,因为这些是Spring AOP的底层技术,清楚了它们,你就更能够理解Spring AOP是如何工作的。在文档的最后简要写了Spring AOP的使用,因为这不是...

Global site tag (gtag.js) - Google Analytics