Spring基础(21)——AOP——动态PointCut

由于动态切入点除了要考虑方法的名称等静态信息外,还要考虑方法的参数。由于它是动态的,在执行时既要计算方法的静态信息,还要计算其参数,结果也不能被缓存。因此,动态切入点要消耗更多的系统资源。

Spring提供的动态切入点的实现:

ControlFlowPointcut:控制流程切入点。例如只有在某个特定的类或方法中调用某个连接点时,装备才会被触发,这时就可以使用ControlFlowPointcut,但是他的系统开销很大,在追求高效的应用中,不推荐使用。

DynamicMethodMatcherPointcut:动态方法匹配器,是抽象类,扩展该类可以实现自己的动态Pointcut。

如果需要自定义切入点可以通过扩展DynamicMethodMatcherPointcut来实现。

ControlFlowPointcut有两个实现类:

ControlFlowPointcut(Class clazz)指定一个类作为流程切入点

ControlFlowPointcut(Class clazz,String methodName)指定一个类和某一个方法作为流程切入点

在上一节中,People的方法并不是全部需要执行。在PeopleDelegate中定义live()方法,执行speak()、talk()方法

package test.pointcut;

public class PeopleDelegate {

	private People people;
	public void setPeople(People people) {
		this.people = people;
	}
	
	public void live() {
		people.speak();
		people.talk();
	}
}
<?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:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
 
	<bean id="peopleTarget" class="test.pointcut.People"></bean>
	<bean id="peopleAdvice" class="test.pointcut.PeopleBeforeAdvice"></bean>

	<bean id="people"
		class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="interceptorNames">
			<idref bean="peopleAdvisor" />
		</property>
		<property name="target" ref="peopleTarget"></property>
	</bean>
	
	<bean id="peopleDelegate" class="org.springframework.aop.support.ControlFlowPointcut">
		<constructor-arg type="java.lang.Class" value="test.pointcut.PeopleDelegate"></constructor-arg>
		<constructor-arg type="java.lang.String" value="live"></constructor-arg>
	</bean>
	<bean id="peopleAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<!-- 
		<property name="patterns">
			<list>
				<value>.*k</value>
			</list>
		</property>-->
		<property name="pointcut" ref="peopleDelegate"></property>
		<property name="advice" ref="peopleAdvice"></property>
	</bean>
	
	
</beans>
package test.pointcut;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-servlet2.xml");
		People people = (People) context.getBean("people");
		
		people.speak();
		people.talk();
		people.run();
		
		PeopleDelegate delegate = new PeopleDelegate();
		delegate.setPeople(people);
		delegate.live();
	}

}
运行结果:
People Speaking
People Talk
People Run
People is speak !
People Speaking
People is talk !
People Talk

对于面向切面,代理对象如PeopleDelegate在每次调用目标方法时,都需要判断方法调用堆栈中是否满足流程切点的要求,因此流程切面对性能的影响特别大,在JVM1.4中,流程切点通常比其他切点慢5倍,在jvm1.3中慢10倍。

如果需要自定义动态切入点,可以通过扩展DynamicMethodMatcherPointcut抽象类,将isRuntime方法表示为final并且放回true,这样就创建了一个动态切入点,该抽象类默认匹配所有类和方法,可以通过扩展该类编写符合要求的动态切入点。


Spring AOPSpring框架中的一个重要模块,它提供了面向切面编程(AOP)的支持。AOP是一种编程思想,它可以在不改变原有代码的情况下,通过在程序运行时动态地将代码“织入”到现有代码中,从而实现对原有代码的增强。 Spring AOP提供了基于注解的AOP实现,使得开发者可以通过注解的方式来定义切面、切点和通知等相关内容,从而简化了AOP的使用。 下面是一个基于注解的AOP实现的例子: 1. 定义切面类 ```java @Aspect @Component public class LogAspect { @Pointcut("@annotation(Log)") public void logPointcut() {} @Before("logPointcut()") public void beforeLog(JoinPoint joinPoint) { // 前置通知 System.out.println("执行方法:" + joinPoint.getSignature().getName()); } @AfterReturning("logPointcut()") public void afterLog(JoinPoint joinPoint) { // 后置通知 System.out.println("方法执行完成:" + joinPoint.getSignature().getName()); } @AfterThrowing(pointcut = "logPointcut()", throwing = "ex") public void afterThrowingLog(JoinPoint joinPoint, Exception ex) { // 异常通知 System.out.println("方法执行异常:" + joinPoint.getSignature().getName() + ",异常信息:" + ex.getMessage()); } } ``` 2. 定义业务逻辑类 ```java @Service public class UserService { @Log public void addUser(User user) { // 添加用户 System.out.println("添加用户:" + user.getName()); } @Log public void deleteUser(String userId) { // 删除用户 System.out.println("删除用户:" + userId); throw new RuntimeException("删除用户异常"); } } ``` 3. 在配置文件中开启AOP ```xml <aop:aspectj-autoproxy/> <context:component-scan base-package="com.example"/> ``` 在这个例子中,我们定义了一个切面类LogAspect,其中通过@Aspect注解定义了一个切面,通过@Pointcut注解定义了一个切点,通过@Before、@AfterReturning和@AfterThrowing注解分别定义了前置通知、后置通知和异常通知。 在业务逻辑类中,我们通过@Log注解标注了需要增强的方法。 最后,在配置文件中,我们通过<aop:aspectj-autoproxy/>开启了AOP功能,并通过<context:component-scan>扫描了指定包下的所有组件。 这样,当我们调用UserService中的方法时,就会触发LogAspect中定义的通知,从而实现对原有代码的增强。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值