AOP_使用CGLIB实现AOP功能

本文介绍如何使用CGLIB库实现代理模式,通过创建目标对象的子类来拦截并增强业务层方法,实现AOP功能。示例中演示了如何通过CGLIB拦截PersonServiceImp类的所有方法,并在调用前进行权限检查。

好处:不需要目标对象实现接口

使用的架包:cglib-nodep-2.1_3.jar

实例:使用CGLIB实现AOP功能

         拦截所以业务层方法,模拟用户验证(用户为null,即没用权限)

PersonServiceImp.java

/**
 * 业务层,被拦截对象
 */
package com.qh.service.imp;
public class PersonServiceImp {
	String user = null;//用户
	// 获得用户信息的方法
	public String getUser() {
		return user;
	}

	public PersonServiceImp() {
	}

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

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

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

	public String getPersonName(int id) {
		return "我是getPersonName()方法";
	}

}

 CGlibProxyFactory.java

package com.qh.aop;

import java.lang.reflect.Method;

import com.qh.service.imp.PersonServiceImp;

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

public class CGlibProxyFactory implements MethodInterceptor{
	private Object targetObject;//目标对象
	//创建代理对象
	public Object createProxyIntance(Object targetObject){
		this.targetObject=targetObject;
		//创建代理对象
		Enhancer enhancer=new Enhancer();
		/*
		 * 设置其父类,即目标类;这时他会产生一个目标类的子类,
		 * 该子类可以覆盖父类中所有非final的方法,并添加一些自身的代码
		 */
		enhancer.setSuperclass(this.targetObject.getClass());
		//设置回调,并需要实现MethodInterceptor接口,回调intercept()方法
		enhancer.setCallback(this);
		return enhancer.create();//返回一个代理对象
	}
	//接口中的方法
	//参数说明:代理对象本身、被拦截到的方法、方法的输入参数、方法的代理对象
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		PersonServiceImp personServiceImp=(PersonServiceImp)this.targetObject;
		Object result=null;
		if(personServiceImp.getUser()!=null){
			result=methodProxy.invoke(this.targetObject, args);
		}
		return result;
	}
}

 AOPTest.java

package com.qh.test;
import org.junit.Test;
import com.qh.aop.CGlibProxyFactory;
import com.qh.service.imp.PersonServiceImp;

public class AOPTest {

	@Test
	public void test() {
		CGlibProxyFactory cGlibProxyFactory = new CGlibProxyFactory();
		//cGlibProxyFactory创建的类是PersonServiceImp的子类
		PersonServiceImp imp = (PersonServiceImp) cGlibProxyFactory
				.createProxyIntance(new PersonServiceImp("xh"));
		imp.save("熊晖");
	}

}

 

<think>我们正在讨论如何在Spring AOP使用CGLIB代理。根据引用[1]和[2],我们知道Spring AOP默认使用JDK动态代理,但如果目标类没有实现接口,则会使用CGLIB代理。同时,我们也可以强制Spring AOP使用CGLIB代理。 在Spring AOP中配置使用CGLIB代理有两种方式: 1. 通过XML配置:在aop:config元素中设置proxy-target-class="true" 2. 通过注解配置:使用@EnableAspectJAutoProxy(proxyTargetClass = true) 下面我们分别详细说明: 一、XML配置方式 在Spring的XML配置文件中,添加如下配置: ```xml <aop:config proxy-target-class="true"> <!-- 其他aop配置 --> </aop:config> ``` 或者,如果你使用了自动代理,可以这样设置: ```xml <aop:aspectj-autoproxy proxy-target-class="true"/> ``` 二、注解配置方式 在Java配置类上,使用@EnableAspectJAutoProxy注解,并设置proxyTargetClass属性为true: ```java @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) public class AppConfig { // 配置类内容 } ``` 这样配置后,Spring AOP就会使用CGLIB来创建代理,无论目标类是否实现了接口。 三、示例 下面是一个完整的示例,展示如何在Spring AOP使用CGLIB代理: 1. 目标类(没有实现接口): ```java public class UserService { public void addUser(String name) { System.out.println("添加用户: " + name); } } ``` 2. 切面类: ```java @Aspect public class LoggingAspect { @Before("execution(* addUser(..))") public void beforeAddUser(JoinPoint joinPoint) { System.out.println("准备添加用户"); } } ``` 3. 配置类(使用注解方式强制CGLIB代理): ```java @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @ComponentScan(basePackages = "com.example") public class AppConfig { @Bean public LoggingAspect loggingAspect() { return new LoggingAspect(); } } ``` 4. 测试类: ```java public class Main { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); userService.addUser("张三"); } } ``` 运行测试,输出将会是: ``` 准备添加用户 添加用户: 张三 ``` 注意:由于我们使用CGLIB代理,Spring会生成UserService的子类,并重写方法以加入切面逻辑。因此,目标类不能是final类,否则无法生成子类。 引用说明: - 引用[1]指出CGLIB通过继承被代理类来创建代理对象,因此不需要实现接口。 - 引用[4]提到Spring在运行时使用CGLIB代理生成代理类,在目标方法执行前后插入切面代码。 通过以上配置,我们就成功在Spring AOP使用CGLIB代理。 §§相关问题§§ 1. Spring AOP默认使用什么代理方式? 2. 在什么情况下Spring AOP会自动切换到CGLIB代理? 3. 使用CGLIB代理有什么限制? 4. 如何判断一个Bean是否被CGLIB代理? 5. CGLIB代理和JDK动态代理在性能上有什么区别?</think>在 Spring AOP 中配置和使用 CGLIB 代理主要涉及以下关键步骤和配置方式,这些方法可确保 Spring 使用 CGLIB 而非默认的 JDK 动态代理: ### 一、配置方式 1. **XML 配置** 在 Spring 配置文件中显式启用 CGLIB: ```xml <!-- 方式1:全局启用 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 方式2:在config中启用 --> <aop:config proxy-target-class="true"> <!-- 切面配置 --> </aop:config> ``` 2. **注解配置** 在 Java 配置类中使用 `@EnableAspectJAutoProxy`: ```java @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB @ComponentScan(basePackages = "com.example") public class AppConfig { // 其他配置 } ``` ### 二、使用场景 当以下情况出现时,Spring 会自动切换至 CGLIB 代理: 1. 目标类**未实现任何接口**(默认行为)[^1] 2. 显式设置 `proxy-target-class=true`(强制使用) 3. 需要拦截 `final` 方法(需特殊配置) ### 三、完整示例 ```java // 1. 目标类(无接口) @Component public class UserService { public void createUser(String name) { System.out.println("创建用户: " + name); } } // 2. 切面定义 @Aspect @Component public class LoggingAspect { @Before("execution(* createUser(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("[AOP] 开始创建用户: " + Arrays.toString(joinPoint.getArgs())); } } // 3. 配置类(强制CGLIB) @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @ComponentScan public class AppConfig {} // 4. 测试 public class Main { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); UserService service = ctx.getBean(UserService.class); service.createUser("张三"); // 输出拦截日志 } } ``` 输出结果: ``` [AOP] 开始创建用户: [张三] 创建用户: 张三 ``` ### 四、关键注意事项 1. **类限制** - 目标类不能是 `final`(CGLIB 通过子类化实现代理) - 无法拦截 `private`/`static` 方法(CGLIB 继承机制限制)[^2] 2. **性能优化** - 添加 `spring-core` 依赖(内含 CGLIB repackaged 版本) - 对频繁调用的方法启用缓存: ```xml <aop:config proxy-target-class="true"> <aop:aspect ref="myAspect"> <aop:around method="cache" pointcut="execution(* highFrequencyMethod(..))"/> </aop:aspect> </aop:config> ``` 3. **与 JDK 代理对比** | **特性** | **CGLIB** | **JDK 动态代理** | |------------------|-------------------------------|--------------------------| | 代理机制 | 继承目标类生成子类 | 实现相同接口 | | 目标类要求 | 非 final 类 | 必须实现接口 | | 方法拦截范围 | 所有 public/protected 方法 | 仅接口定义的方法 | | 性能 | 首次创建慢,执行快 | 创建快,执行稍慢 | > 提示:在 Spring Boot 中默认优先使用 CGLIB,无需额外配置[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值