应用——>代理对象——>目标对象
使用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.
分享到:
相关推荐
在Spring AOP中,如果目标对象实现了至少一个接口,那么Spring会选择使用JDK Proxy。以下是一个简单的示例: ```java public interface MyService { void doSomething(); } public class MyServiceImpl ...
下面我们将深入理解CGLIB在Spring AOP中的工作原理以及如何配置和使用它。 首先,了解AOP的基本概念是必要的。AOP通过切面(Aspect)来封装横切关注点,这些关注点通常涉及到多个对象和方法。切面可以包含通知...
在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...
静态代理--不适合企业开发,适合初学者理解代理。 jdk动态代理--适合企业级开发,但是它要求必须面向接口编程,假如目标类没有实现接口...spring 的AOP功能中 会根据目标类是否实现了接口来判断使用 jdk Proxy还是cglib
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 如何强制使用CGLIB实现AOP? * 添加CGLIB库,SPRING_HOME/...
在实际开发中,如Spring AOP框架就同时支持JDK和CGLIB动态代理,根据目标类是否实现接口自动选择合适的代理方式。 总结来说,JDK动态代理和CGLIB动态代理都是为了在运行时提供对目标对象的增强,它们通过不同的实现...
在Spring AOP中,CGLIB代理的主要优点是它不需要目标对象实现任何接口,因此对于没有接口或者接口较少的类,CGLIB是一种很好的选择。然而,它的缺点是生成的代理类会稍微增加内存占用,且由于是通过继承实现,如果...
Spring的AOP实现有两种方式:JDK动态代理和CGLIB字节码代理。当目标对象实现了一个或多个接口时,Spring会选择使用JDK动态代理。以下是Spring AOP使用JDK动态代理的基本步骤: 1. **创建代理对象**:Spring会创建一...
- **性能**:Cglib通常比JDK动态代理更快,因为它使用字节码生成子类,而JDK则需要创建接口的实现类。 - **灵活性**:JDK代理要求目标类实现接口,而Cglib无此限制。 - **使用场景**:如果目标类已经实现了接口,且...
5. **配置代理**:Spring会根据目标对象是否实现了接口来决定使用JDK动态代理还是CGLIB代理。如果目标对象实现了接口,Spring会选择JDK动态代理。动态代理类会继承自`java.lang.reflect.Proxy`,并实现目标对象的...
CGLIB是一个第三方的字节码生成库,广泛应用于Spring AOP框架中,可以为没有实现接口的类创建代理。 1. **原理**:CGLIB通过ASM库在运行时动态生成一个目标类的子类,从而实现对目标对象的方法拦截。这个子类重写了...
拦截器(Interceptor)是AOP(面向切面编程)的一个重要概念,通常在框架中使用,如Spring AOP。拦截器可以理解为在方法调用前后插入额外行为的“钩子”。在拦截器链中,多个拦截器可以按照特定顺序执行,形成一种...
在Java中,CGlib是一个非常重要的工具,特别是在AOP(面向切面编程)和ORM(对象关系映射)框架中,如Spring和Hibernate广泛使用它来实现代理功能。 CGlib动态代理的工作原理是通过继承被代理的目标类来创建子类,...
在Java中,我们可以使用JDK自带的动态代理或者第三方库如CGLIB、Javassist、ASM来实现。 **JDK动态代理**: JDK的动态代理主要依赖于`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`两个类。...
CGLIB是一个强大的高性能的代码生成库,它在许多AOP框架中如Spring AOP中被使用。以下是CGLIB的一些关键知识点: 1. **CGLIB包**:CGLIB包含在Spring的`spring-core`模块中,主要使用`net.sf.cglib.proxy.Enhancer`...
Spring AOP则是在Spring框架中对AOP概念的实现,它利用了JDK动态代理或CGLIB(字节码增强)来实现。Spring AOP的主要目标是分离关注点,将非业务逻辑(如日志、事务管理)从核心业务代码中解耦出来。以下是Spring ...
在Java中,代理模式有多种实现方式,包括静态代理、JDK动态代理和CGLIB动态代理。 **静态代理** 静态代理是最早也是最基础的代理实现方式。在静态代理中,我们需要创建一个代理类,这个代理类与原始类(被代理类)...
JDK和CGLIB是Java中实现动态代理的两种主要方式,它们在Spring框架中扮演着关键角色,尤其是在AOP(面向切面编程)中。 1. **JDK动态代理**: JDK动态代理基于Java的接口机制实现,因此,要使用JDK动态代理,被...
Cglib就是一种实现动态代理的方式,不同于JDK自带的Proxy,Cglib不需要目标对象实现任何接口,因此可以用于不能实现接口的对象。通过Enhancer类,我们可以指定需要代理的目标类,并提供回调方法实现动态代理逻辑。 ...
JDK和CGlib是两种常用的动态代理实现方式,它们各自有不同的特性和使用场景。 首先,我们来详细了解一下JDK动态代理。JDK动态代理基于接口实现,它要求被代理的对象必须实现至少一个接口。通过`java.lang.reflect....