Spring AOP 入门

本文详细介绍了面向切面编程(AOP)的概念、优势及其在Spring框架中的应用。通过实例演示了如何利用AOP进行方法增强,并展示了不同类型的动态代理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 *	AOP概述:面向切面编程
 *		将共性的进行抽取,在需要的地方进行动态代理的插入,在不修改源码的基础上,还能对代码进行增强
 *	AOP的作用及优势
 *		作用:在程序运行期间,不修改源码对方法的增强。
 *		优势:a.减少代码的重读b.提高开发效率c.方便维护
 *	动态代理的特点:
 *		字节码随用随创建,随用随加载 ->它与静态代理的区别 静态代理是字节码一上来就加载好的,并完成加载
 *		装饰者模式就是静态代理一种体现
 *	动态代理常用的有两种方式
 *		a.基于接口动态代理
 *			提供者:JDK官方的Proxy类
 *			要求:被代理类最少实现一个接口
 *		b.基于子类的动态代理
 *			提供者:第三方的CGLib,需要导入asm.jar
 *			要求:被代理类不能用final修饰类
 * 		cglib 是第三方动态代理 单独用需要导包的
 * 		AOP底层的实现用的是:自适应
 * 			如果有接口 优先使用jdk的动态代理
 * 			如果没有接口优先用cglib的动态代理
 * 
 * AOP的全xml配置
 * 		连接点:可以被增强的方法
 * 		切入点:要被增强的方法	(例如:person对象有save update delete) 但只想对save方法增强
 * 			   那么我们可以把这个save方法作为切入点
 * 		通知/增强:增强的那段代码方法
 * 		切面:切入点+通知/增强 = 切面	(目标方法和增强方法合成在一起 叫切面)
 * 		织入:将切入集成到切面的这一过程 我们称为织入过程
 * @author zx
 *
 */

先用代理对象举个例子

定义一个普通类

package xinfei.code.proxytest;

public interface User {
	/**
	 * 吃饭
	 */
	public void eat();
	/**
	 * 保存
	 */
	public void save();
}
实现类

package xinfei.code.proxytest;

public class UserImpl implements User {

	@Override
	public void eat() {
		System.out.println("吃饭...");
	}

	@Override
	public void save() {
		System.out.println("保存...");
	}
}
Junit测试

public class UserTest {

	@Test
	public void test01(){
		//目标对象
		User user = new UserImpl();
		//要增强的方法
		user.eat();
	}
	
	@Test
	public void test02(){
		final UserImpl user = new UserImpl();
		User userProxy = (User)Proxy.newProxyInstance(
				//和目标对象一样的类加载器
				user.getClass().getClassLoader(), 
				//和目标对象一样的接口   因为代理类要实现和目标一样的接口
				user.getClass().getInterfaces(),
				new InvocationHandler() {
					//参数1.代理对象类型 忽视	//参数2.目标对象要增强的方法	//参数3.目标对象运行方法时需要的参数
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						if("eat".equals(method.getName())){
							Object invoke = method.invoke(user, args);
							System.out.println(invoke);
							System.out.println("增强饭后 看电视");
						}else if("save".equals(method.getName())){
							Object invoke = method.invoke(user, args);
							System.out.println(invoke);
							System.out.println("增强的save方法");
						}else{
							method.invoke(user, args);
						}
						return null;
					}
				});
		userProxy.eat();
		userProxy.save();
	}
}
然后使用配置文件案例

定义一个类

package xinfei.code.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
	
	//增强方法   方法前
	public void beforeMethod(){
		System.out.println("--beforeMethod--");
	}
	
	public void afterMethod(){
		System.out.println("--afterMethod--");
	}
	
	public void afterreturningMethod(){
		System.out.println("--afterreturningMethod--");
	}
	
	public void aroudMethod(ProceedingJoinPoint pdj) throws Throwable{
		System.out.println("之前增强");
		pdj.proceed();
		System.out.println("之后增强");
	}
}
package xinfei.code.proxytest;

public class Person {
	public void save(){
		System.out.println("save...");
	}
	public void find(){
		System.out.println("find...");
	}
	public void delete(){
		System.out.println("delete...");
	}
	public void update(){
		System.out.println("update...");
	}
}
applicationContext.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd">
		
		<!-- 目标类 里面有切入点 要增强的方法 -->
        <bean id="person" class="xinfei.code.proxytest.Person"></bean>
        <!-- 切面类 里面有通知/增强 -->
        <bean id="myaspect" class="xinfei.code.aspect.MyAspect"></bean>
		
		<aop:config>
			<aop:aspect ref="myaspect">
				<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.save(..))" id="cut1"/>
				<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.find(..))" id="cut2"/>
				<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.update())" id="cut3"/>
				<aop:pointcut expression="execution(void xinfei.code.proxytest.Person.delete())" id="cut4"/>
				<!-- 之前通知 -->
				<aop:before method="beforeMethod" pointcut-ref="cut1"/>
				<!-- 之后通知 -->
				<aop:after-returning method="afterreturningMethod" pointcut-ref="cut2"/>
				<!-- 环绕,前后通知 -->
				<aop:around method="aroudMethod" pointcut-ref="cut3"/>
				<aop:after method="afterMethod" pointcut-ref="cut4"/>
			</aop:aspect>
		</aop:config>
</beans>

Junit测试

package xinfei.code.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import xinfei.code.proxytest.Person;

@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class PersonTest {

	@Autowired
	private Person person;
	
	@Test
	public void test01(){
		person.delete();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值