`

使用JDK中的Proxy技术、CGLIB实现AOP功能

阅读更多

应用——>代理对象——>目标对象
使用Proxy创建代理对象时,目标对象必须实现某个接口,不然会报错!
当目标对象没有实现接口时,可以使用Spring中的/lib/cglib/cglib-nodep.jar来创建代理对象!

一、使用JDK中的Proxy技术实现AOP功能

1。创建一个接口PersonService以及该接口的实现类PersonServiceBean ,PersonService 代码如下:

package cn.reiyen.aop;

public interface PersonService {
	public void save(String name);
	public void update(String name, int id);
}

PersonServiceBean的 代码如下:

package cn.reiyen.aop;

public class PersonServiceBean  implements PersonService{
	private String user = null;

	public PersonServiceBean() {
	}

	public PersonServiceBean(String user) {
		this.user = user;
	}

	public String getUser() {
		return user;
	}

	public void save(String name) {
		System.out.println("我是save()方法" + name);
	}

	public void update(String name, int id) {
		System.out.println("我是update()方法!");
	}
}

需求如下:如果实现类的user!=null,才可以调用save与update方法,为null则不能调用。当然要解决此问题,可以在save与update方法内部进行判断,但是如果在方法内部进行判断,代码则失去了灵活性,如果以后的需求改变,比如变成user.equals时,则又要在update/save方法中重新进行一次判断。如果save/update这样的方法很多,这样就会很麻烦。其实要解决此问题,可以通过动态代理技术实现。这里的需求其实就是根据要求来拦截一些业务方法,这种编程问题称之为横切性关注点。

2。动态代理实现[JDK]

建立代理工厂JDKProxyFactory ,代码如下:

package cn.reiyen.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyFactory implements InvocationHandler {
	private Object targetObject;
	public Object createProxyInstance(Object targetObject){
		this.targetObject = targetObject;
		//创建一个代理对象,此对象是一个与目标对象实现了相同接口的对象。第一个参数为目标对象的类装载器,第二个参数为目标对象所实现的所有接口,第三个参数为实现了InvocationHandler接口的对象实例,在这里即为JDKProxyFactory自身
return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), 
				this.targetObject.getClass().getInterfaces(), this);
	}
//第一个参数为代理对象,第二个参数被拦截到的方法,第三个参数为拦截到的方法的输入参数;代理对象最后又将拦截到的方法的处理委配回给目标对象自己处理
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {//环绕通知
		PersonServiceBean bean = (PersonServiceBean)this.targetObject;
		Object result = null;
		if(bean.getUser() != null){
		//….advice()-->前置通知	
               try{
                  result = method.invoke(bean, args);
                 //….afteradvice()-->后置通知
               }catch(RuntimeException e){
                      //….exceptionadvice()-->例外通知
             }finally{
                     //….finallyadvice()-->最终通知
             }
		}
		return result;
	}
}

 
简析动态代理:此类根据传递的targetObject对象来生成此目标对象的代理对象,需要强调的是动态代理技术所要代理的对象必须实现一个接口。newProxyInstance参数说明:第一个参数是目标对象的类装载器,第二个参数是目标对象的接口,第三个参数是回调对象,生成的代理对象要执行方法时就是依靠这个回调对象的invoke方法来进行目标对象的方法回调。关于动态代理的其它细节不在此讨论。

 

3.建立junit测试代码,内容如下:

public class AOPTest1 {

@Test  //用户名为空,不执行save方法
public void proxyTest1(){
		JDKProxyFactory factory = new JDKProxyFactory();
		PersonService service = (PersonService) factory.createProxyInstance(new PersonServiceBean());
		service.save("888");
	}
@Test  //用户名为不为空,才执行save方法,
public void proxyTest2(){
		JDKProxyFactory factory = new JDKProxyFactory();
		PersonService service = (PersonService) factory.createProxyInstance(new PersonServiceBean("xxlong"));
		service.save("888");
	}
}

 测试结果:测试1能通过,但不会执行save()方法,所以不会打印出信息提示语句。

测试1能通过,且会执行save()方法,所以打印出信息提示语句:我是save()方法888

在写测试代码时要注意,创建的代理对象只要转化为接口PersonService,而不能转化为PersonServiceBean.因为newProxyInstance方法返回的是一个指定接口的代理类实例,如果测试代码写成如下:

PersonServiceBean service = (PersonServiceBean) factory.createProxyInstance(new PersonServiceBean("xxx"));

 则会出错,出借信息如下:java.lang.ClassCastException: $Proxy5 cannot be cast to cn.reiyen.aop.PersonServiceBean。

注:newProxyInstance方法详细说明:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。此方法相当于:
     Proxy.getProxyClass(loader, interfaces).
         getConstructor(new Class[] { InvocationHandler.class }).
         newInstance(new Object[] { handler });
 
Proxy.newProxyInstance 抛出 IllegalArgumentException,原因与 Proxy.getProxyClass 相同。
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口

 

二、使用CGLIB实现AOP功能

JDK的Proxy实现代理要求被代理的目标对象必须实现一个接口,而如果目标对象没有实现接口则不能使用Proxy来代理。这时可以借助spring中的cglib jar包来实现代理。CGLIB可以生成目标类的子类,并重写父类的非final修饰符的方法.操作步骤如下:

步骤一、建立PersonServiceBean2类,它与PersonServiceBean的唯一区别就是没有实现任何接口。
步骤二、导入cglib.jar包,创建cglib代理工厂,代码如下:

package cn.reiyen.aop;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGLibFactory implements MethodInterceptor {
	
	private Object targetObject; //代理的目标对象
	
	public Object createProxyInstance(Object tarObject){
		this.targetObject = tarObject;
		Enhancer enhancer = new Enhancer(); //该类用于生成代理器类
		
		//将目标类指定为代理类的父类,产生的代理类是此目标类的一个子类,
		//产生的这个子类会覆盖此目标类中的所有的非final修饰的方法
		enhancer.setSuperclass(this.targetObject.getClass());
		enhancer.setCallback(this); //设置回调对象为本身
		return enhancer.create();
	}

	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		PersonServiceBean2 bean = (PersonServiceBean2) this.targetObject;
		Object result = null;
		if(bean.getUser() != null){
			result = methodProxy.invoke(targetObject, args);
		}
		return result;
	}
}

 步骤三、建立测试代码:

	@Test 
	public void cglibProxyTest(){
		CGLibFactory factory = new CGLibFactory();
		PersonServiceBean2 service = (PersonServiceBean2) factory.createProxyInstance(new PersonServiceBean2("xxlong"));
		service.save("999");
	}

 这时因为CGLIB生成的目标类PersonServiceBean2的子类,所以应该把创建的代理对象转化成PersonServiceBean2.

 

 

分享到:
评论

相关推荐

    使用JDK中的Proxy技术实现AOP功能与使用CGLIB实现AOP功能

    在Spring AOP中,如果目标对象实现了至少一个接口,那么Spring会选择使用JDK Proxy。以下是一个简单的示例: ```java public interface MyService { void doSomething(); } public class MyServiceImpl ...

    Spring学习笔记(14)----使用CGLIB实现AOP功能

    下面我们将深入理解CGLIB在Spring AOP中的工作原理以及如何配置和使用它。 首先,了解AOP的基本概念是必要的。AOP通过切面(Aspect)来封装横切关注点,这些关注点通常涉及到多个对象和方法。切面可以包含通知...

    浅谈JDK动态代理与CGLIB代理去区别

    在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...

    cglib aop spring 动态代理

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

    spring_aop4.rar_Home Home_jar 转换_spring AOP jar

    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 如何强制使用CGLIB实现AOP? * 添加CGLIB库,SPRING_HOME/...

    Jdk动态代理和cglib动态代理原理

    在实际开发中,如Spring AOP框架就同时支持JDK和CGLIB动态代理,根据目标类是否实现接口自动选择合适的代理方式。 总结来说,JDK动态代理和CGLIB动态代理都是为了在运行时提供对目标对象的增强,它们通过不同的实现...

    spring_aop_cglib的实现方式

    在Spring AOP中,CGLIB代理的主要优点是它不需要目标对象实现任何接口,因此对于没有接口或者接口较少的类,CGLIB是一种很好的选择。然而,它的缺点是生成的代理类会稍微增加内存占用,且由于是通过继承实现,如果...

    从JDK动态代理看Spring之AOP实现

    Spring的AOP实现有两种方式:JDK动态代理和CGLIB字节码代理。当目标对象实现了一个或多个接口时,Spring会选择使用JDK动态代理。以下是Spring AOP使用JDK动态代理的基本步骤: 1. **创建代理对象**:Spring会创建一...

    JDK动态代理和Cglib动态代理实例源码

    - **性能**:Cglib通常比JDK动态代理更快,因为它使用字节码生成子类,而JDK则需要创建接口的实现类。 - **灵活性**:JDK代理要求目标类实现接口,而Cglib无此限制。 - **使用场景**:如果目标类已经实现了接口,且...

    Spring-AOP-JDK动态代理

    5. **配置代理**:Spring会根据目标对象是否实现了接口来决定使用JDK动态代理还是CGLIB代理。如果目标对象实现了接口,Spring会选择JDK动态代理。动态代理类会继承自`java.lang.reflect.Proxy`,并实现目标对象的...

    jdk与cglib动态度代理的区别原理

    CGLIB是一个第三方的字节码生成库,广泛应用于Spring AOP框架中,可以为没有实现接口的类创建代理。 1. **原理**:CGLIB通过ASM库在运行时动态生成一个目标类的子类,从而实现对目标对象的方法拦截。这个子类重写了...

    Jdk动态代理,cglib动态代理,反射和拦截器(链)示例

    拦截器(Interceptor)是AOP(面向切面编程)的一个重要概念,通常在框架中使用,如Spring AOP。拦截器可以理解为在方法调用前后插入额外行为的“钩子”。在拦截器链中,多个拦截器可以按照特定顺序执行,形成一种...

    CGlib实现动态代理(承接上面JDK实现动态代理)

    在Java中,CGlib是一个非常重要的工具,特别是在AOP(面向切面编程)和ORM(对象关系映射)框架中,如Spring和Hibernate广泛使用它来实现代理功能。 CGlib动态代理的工作原理是通过继承被代理的目标类来创建子类,...

    Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    在Java中,我们可以使用JDK自带的动态代理或者第三方库如CGLIB、Javassist、ASM来实现。 **JDK动态代理**: JDK的动态代理主要依赖于`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`两个类。...

    JAVA动态代理实现Demo(JDK动态代理和CGLIB动态代理)

    CGLIB是一个强大的高性能的代码生成库,它在许多AOP框架中如Spring AOP中被使用。以下是CGLIB的一些关键知识点: 1. **CGLIB包**:CGLIB包含在Spring的`spring-core`模块中,主要使用`net.sf.cglib.proxy.Enhancer`...

    JDK动态代理 spring aop 的原理

    Spring AOP则是在Spring框架中对AOP概念的实现,它利用了JDK动态代理或CGLIB(字节码增强)来实现。Spring AOP的主要目标是分离关注点,将非业务逻辑(如日志、事务管理)从核心业务代码中解耦出来。以下是Spring ...

    代理模式-静态动态代理-jdk动态代理-cglib动态代理

    在Java中,代理模式有多种实现方式,包括静态代理、JDK动态代理和CGLIB动态代理。 **静态代理** 静态代理是最早也是最基础的代理实现方式。在静态代理中,我们需要创建一个代理类,这个代理类与原始类(被代理类)...

    jdk与cglib动态代理与底层实现

    JDK和CGLIB是Java中实现动态代理的两种主要方式,它们在Spring框架中扮演着关键角色,尤其是在AOP(面向切面编程)中。 1. **JDK动态代理**: JDK动态代理基于Java的接口机制实现,因此,要使用JDK动态代理,被...

    Cglib3.3.0最新版jar包

    Cglib就是一种实现动态代理的方式,不同于JDK自带的Proxy,Cglib不需要目标对象实现任何接口,因此可以用于不能实现接口的对象。通过Enhancer类,我们可以指定需要代理的目标类,并提供回调方法实现动态代理逻辑。 ...

    JDK和CGlib分别实现的动态代理源代码

    JDK和CGlib是两种常用的动态代理实现方式,它们各自有不同的特性和使用场景。 首先,我们来详细了解一下JDK动态代理。JDK动态代理基于接口实现,它要求被代理的对象必须实现至少一个接口。通过`java.lang.reflect....

Global site tag (gtag.js) - Google Analytics