《精通Spring-4.x》Spring AOP

本文详细解析了AOP的基本概念,包括连接点、切点、增强、目标对象、引介、织入和切面,并介绍了AOP的实现原理。通过具体的代码示例,演示了如何在Spring框架中创建各种类型的增强,如前置、后置、环绕、异常抛出和引介增强。此外,还探讨了切面的创建方法,包括静态、动态、流程、复合切点和引介切面。最后,文章讲解了如何使用AspectJ和基于schema的配置来实现切面。

目录

  1. AOP相关概念
  2. AOP的实现原理
  3. 创建增强类
  4. 创建切面
  5. 通过AspectJ实现切面
  6. 基于schema配置切面

一、AOP的相关概念

  • 连接点 按照我的理解,连接点就是程序中的一个个方法(因为在Spring中仅支持方法的连接点),只能在方法的调用前后,方法抛出异常等地方织入增强。Spring中使用切点对执行点进行定位,方位定义在增强中。
  • 切点:因为程序中存在许多的连接点,则通过切点来定位特定的连接点,在Spring中切点通过org.springframework.aop.Pointcut接口进行描述。
  • 增强:增强是织入目标类连接点上的一段代码,同时增强也包含用于定位连接点的方位信息,所以在Spring中提供的增强接口都是带方位名的,比如BeforeAdvice、AfterReturningAdvice等。
  • 目标对象:增强的织入目标类
  • 引介:引介是一种特殊的增强,他为类添加一些属性和方法。利用引介,可以动态的为业务类添加其他接口的实现逻辑,让业务类成为这个接口的实现类.
  • 织入:织入是将增强添加到目标类的连接点上的过程。
  • 切面:切点和增强即组成切面
    二、AOP的实现原理
    SPring AOP的底层实现原理为动态代理。Java中提供了两种动态代理方式,JDK动态代理和CGLib动态代理。前者是针对接口的代理,而后者则是针对子类创建动态代理。对于这两种代理的学习,可以参考以下博客。
    https://blog.csdn.net/zs520ct/article/details/79593196
    https://blog.csdn.net/cckevincyh/article/details/54962920
    三、创建增强类
    按照增强在目标类方法中连接点的位置,可以分为如下五类
  • 前置增强
  • 后置增强
  • 环绕增强
  • 异常抛出增强
  • 引介增强
    以下实例均为《精通 Spring 4.x》中的源码
    前置增强
    首先定义一个接口
public interface Waiter {
   void greetTo(String name);
   void serveTo(String name);
}

之后是一个简单的实现类

public class NaiveWaiter implements Waiter {

	public void greetTo(String name) {
		System.out.println("greet to "+name+"...");
	}
	
	public void serveTo(String name){
		System.out.println("serving "+name+"...");
	}
}

接下来是增强类,用来保证NaiveWaiter类在每次执行动作时,都能进行"问候"!

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {
	public void before(Method method, Object[] args, Object obj) throws Throwable {
		String clientName = (String)args[0];
		System.out.println("How are you!Mr."+clientName+".");
	}
}

查看测试结果

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import static org.testng.Assert.*;
import org.testng.annotations.*;

public class BeforeAdviceTest {

    @Test
	public void before() {
        Waiter target = new NaiveWaiter();
        BeforeAdvice  advice = new GreetingBeforeAdvice();
        ProxyFactory pf = new ProxyFactory();
        pf.setInterfaces(target.getClass().getInterfaces());
        pf.setOptimize(true);
        pf.setTarget(target);
        pf.addAdvice(advice);

        Waiter proxy = (Waiter)pf.getProxy(); 
        proxy.greetTo("John");
        proxy.serveTo("Tom");
	}
}

程序的输出结果如下
在这里插入图片描述
如上测试结果,因为只是在目标类target中设置了增强,而没有具体的切点,此时增强是针对目标类中所有方法的。
在如上的测试代码中出现了pf.setOptimize(true); 代码,该方法让ProxyFactory启用代理优化,这样针对接口的代理也会使用CGLib的代理
在Spring中配置

<bean id="greetingBefore" class="com.smart.advice.GreetingBeforeAdvice" />
<bean id="target" class="com.smart.advice.NaiveWaiter" />
<bean id="waiter"
	class="org.springframework.aop.framework.ProxyFactoryBean"
	p:proxyInterfaces="com.smart.advice.Waiter" 
	p:target-ref="target"
	p:interceptorNames="greetingBefore"
/>

ProxyFactory的几个常用的可配置属性
target:代理的目标对象
proxyInterfaces:代理所要实现的接口,可以是多个接口,该属性还有一个别名,interfaces。
interceptorNames:需要织入目标对象的bean列表,采用Bean的名称指定,这些Bean必须实现了 org.aopalliance.interceptor.MethodInteceptor或org.springframework.aop.Advisior的bean
optimize:当设置为true时,强制使用CGLib动态代理。CGLib动态代理在创建时速度慢,但其创建出的代理对象运行效率较高,而JDK动态代理则正相反
proxyTargetClass:是否对类进行代理,当设置为true时,使用CGlib动态代理。
后置增强

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class GreetingAfterAdvice implements AfterReturningAdvice {

	public void afterReturning(Object returnObj, Method method, Object[] args,
			Object obj) throws Throwable {
		System.out.println("Please enjoy yourself!");
	}
}
<bean id="waiter"
	class="org.springframework.aop.framework.ProxyFactoryBean"
	p:proxyInterfaces="com.smart.advice.Waiter"
	p:target-ref="target"
	p:interceptorNames="greetingBefore,greetingAfter"
/>

执行结果如下
在这里插入图片描述
环绕增强

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class GreetingInterceptor implements MethodInterceptor {

	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object[] args = invocation.getArguments();
		String clientName = (String)args[0];
		System.out.println("How are you!Mr."+clientName+".");
		
		Object obj = invocation.proceed();
		
		System.out.println("Please enjoy yourself!");
		
		return obj;
	}
}

异常抛出增强
首先定义一个异常抛出类

import java.sql.SQLException;

public class ForumService {
	public void removeForum(int forumId) {
		// do sth...
		throw new RuntimeException("运行异常。");
	}
	public void updateForum(Forum forum) throws Exception{
		// do sth...
		throw new SQLException("数据更新操作异常。");
		
	}
}

接下来定义异常抛出增强

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;

public class TransactionManager implements ThrowsAdvice {
	public void afterThrowing(Method method, Object[] args, Object target,
			Exception ex) throws Throwable {
		System.out.println("-----------");
		System.out.println("method:" + method.getName());
		System.out.println("抛出异常:" + ex.getMessage());
		System.out.println("成功回滚事务。");
	}
}

ThrowsAdvice是一个标签接口,它没有定义任何方法,它必须采用以下形式定义增强方法

void afterThrowing(Method method, Object[] args, Object target,
			Throwable th) 

在此方法中前三个参数要么提供,要么不提供,最后一个参数为Throwable或其子类。
引介增强
引介增强是一种比较特殊的增强类型,他不是在目标方法周围织入增强,而是为目标类创建新的方法和属性。引介增强的连接点是类级别的。
Spring定义了引介增强增强接口IntroductionInteceptor,该接口没有定义任何方法,Spring为该接口提供了DelegatingIntroductionInteceptor实现类,一般情况下通过扩展该实现类定义自己的引介增强类。
以下为引介增强的实现实例,实现性能监视功能可控。
首先定义一个用于标识目标类是否支持性能监视的接口。

public interface Monitorable {
   void setMonitorActive(boolean active);
}

下面通过扩展DelegatingIntroductionInteceptor为目标类引入性能监视的可控功能。

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class ControllablePerformaceMonitor
		extends
			DelegatingIntroductionInterceptor implements Monitorable, Testable {
	private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();
	public void setMonitorActive(boolean active) {
		MonitorStatusMap.set(active);
	}
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object obj = null;
		if (MonitorStatusMap.get() != null && MonitorStatusMap.get()) {
			PerformanceMonitor.begin(mi.getClass().getName() + "."
					+ mi.getMethod().getName());
			obj = super.invoke(mi);
			PerformanceMonitor.end();
		} else {
			obj = super.invoke(mi);
		}
		return obj;
	}
	public void test() {
		// TODO Auto-generated method stub
		System.out.println("dd");
	}
}

接下来配置引介增强

	<bean id="pmonitor" class="com.smart.introduce.ControllablePerformaceMonitor" />
	<bean id="forumServiceTarget" class="com.smart.introduce.ForumService" />
	<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interfaces="com.smart.introduce.Monitorable"
		p:target-ref="forumServiceTarget"
		p:interceptorNames="pmonitor" 
		p:proxyTargetClass="true" />

在配置中,首先通interfaces属性配置所要实现的接口,因为是通过为目标类创建子类的方式生成引介增强的代理,所以必须将proxyTargetClass属性设置为true。
以下为测试类。

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.testng.Assert.*;
import org.testng.annotations.*;
public class IntroduceTest {

    @Test
	public void introduce(){
		String configPath = "com/smart/introduce/beans.xml";
		ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
        ForumService forumService = (ForumService)ctx.getBean("forumService");
        forumService.removeForum(10);
        forumService.removeTopic(1022);
        Monitorable moniterable = (Monitorable)forumService;
        moniterable.setMonitorActive(true);
        forumService.removeForum(10);
        forumService.removeTopic(1022); 
	}
}

其输出信息如下。
在这里插入图片描述
四、创建切面
在上一小节中说明了如何创建增强,因为没有切点的原因,所以增强就织入了目标类的所有方法之中。通过定义切点,定位特定的连接点,这样切点和增强就组成了切面。
Spring通过org.springframework.aop.Pointcut接口描述切点,Pointcut由ClassFilter和MethodMatcher定位到某些特定类上,通过MethodMatcher定位到某些特定方法。
在这里插入图片描述
切点类型
静态方法切点:org.springframework.aop.support.StaticMethodMatcherPointcut是静态方法切点的抽象基类,默认情况下它匹配所有的类。StaticMethodMatcherPointcut包括两个主要的子类,分别是NameMatchMethodPointcut和AbstractRegexpMethodPointcut。
动态方法切点:org.springframework.aop.support.DynamicMethodMatcherPointcut是动态方法切点的抽象基类,默认情况下它匹配所有的类。
注解切点:org.springframework.aop.support.annotation.AnnotationMatchingPointcut实现类表示注解切点,该切点支持在Bean中通过注解标签定义切点。
表达式切点:org.springframework.aop.support.ExpressionPointcut接口主要是为了支持AspectJ切点表达式语法而定义的接口。
流程切点 :org.springframework.aop.support.ControlFlowPointcut实现类表示控制流程切点。
复合切点:org.springframework.aop.support.ComposablePointcut实现类是为创建多个切点而提供的方便操作类。
切面类型
Advisior:代表一般切面,仅包含一个Advice,匹配目标类所有方法,一般不会使用。
PointcutAdvisior:代表具有切点的切面。包含Advice和Pointcut两个类,IntroductionAdvisior:代表引介切面,引介切面为对应引介增强的特殊的切面,应用于类层面上。
PointcutAdvisior主要有6个具体的实现类。
DefaultPointcutAdvisior:最常用的切面类型,它可以通过任意Pointcut和Advice定义一个切面,唯一不支持的是引介切面类型。
NameMethodMatcherPointcutAdvisior:对于按正则表达式匹配方法名进行切点定义,可以通过扩展该实现类进行操作。
StaticMethodMatcherPointcutAdvisior:静态方法匹配器定义切面,默认情况下匹配所有目标类。
AspectJExpressionPointcutAdvisior:用于Aspectj切点表达式定义切点的切面。
AspectJPointcutAdvisior:用于Aspectj语法定义切点的切面。
下面通过具体的实例来描述相关切面
静态普通方法名匹配切点
首先定义两个业务类

public class Waiter  {
	public void serveTo(String name){
		System.out.println("waiter serving "+name+"...");
	}

	public void greetTo(String name) {
		System.out.println("waiter greet to "+name+"...");
	}
}
public class Seller {
	public void greetTo(String name) {
		System.out.println("seller greet to "+name+"...");
	}
}

接下来定义具体的切面

import java.lang.reflect.Method;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {

	public boolean matches(Method method, Class clazz) {
		return "greetTo".equals(method.getName());
	}	
	public ClassFilter getClassFilter(){
		return new ClassFilter(){
			public boolean matches(Class clazz){
				return Waiter.class.isAssignableFrom(clazz);
			}
		};
		
	}
}

Advisior还需要一个增强去配合,如下所示。

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {
	public void before(Method method, Object[] args, Object obj) throws Throwable {
		String clientName = (String)args[0];
		System.out.println(obj.getClass().getName()+"."+method.getName());
		System.out.println("How are you!Mr."+clientName+".");
	}
}

最后在Spring配置文件中来定义切面

<bean id="waiterTarget" class="com.smart.advisor.Waiter" />
<bean id="sellerTarget" class="com.smart.advisor.Seller" />
<bean id="greetingAdvice" class="com.smart.advisor.GreetingBeforeAdvice" />
<bean id="greetingAdvisor" class="com.smart.advisor.GreetingAdvisor"
	p:advice-ref="greetingAdvice" />  //向切面注入一个增强
<bean id="parent" abstract="true"
		class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true" />
<bean id="waiter" parent="parent" p:target-ref="waiterTarget" />
<bean id="seller" parent="parent" p:target-ref="sellerTarget" />

StaticMehodMatchPointcutAdvisior除具有advice属性之外,还可以定义另外两个属性。
ClassFilter:类匹配过滤器,在GreetingAdvisior中用编码方式设定了classFilter
order:切面织入时的顺序
这样切面就只会匹配Waiter.greeTo方法。
静态正则表达式方法匹配切面
RegexpMethodPointcutAdvisior是正则表达式方法匹配的切面实现类,该类已经是功能齐备的实现类,一般情况下无需扩展该类。
具体实例如下

<bean id="regexpAdvisor"
	class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
	p:advice-ref="greetingAdvice">
	<property name="patterns">
		<list>
			<value>.*greet.*</value>
		</list>
	</property>
</bean>
<bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean"
	p:interceptorNames="regexpAdvisor" p:target-ref="waiterTarget"
	p:proxyTargetClass="true" />

动态切面
Spring中动态切面可以通过DefaultPointcutAdvisior和DynamicMethodMatcherPointcut,其实例如下。
DynamicMethodMatcherPointcut是一个抽象类,他将isRuntime()标识为final且返回true,这样其子类就一定是一个动态切点。

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.springframework.aop.support.DynamicMethodMatcherPointcut;

public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut {
	private static List<String> specialClientList = new ArrayList<String>();
	static {
		specialClientList.add("John");
		specialClientList.add("Tom");
	}
public ClassFilter getClassFilter() {
	return new ClassFilter() {
		public boolean matches(Class clazz) {
			System.out.println("调用getClassFilter()对"+clazz.getName()+"做静态检查.");
			return Waiter.class.isAssignableFrom(clazz);
		}
	};
}
	public boolean matches(Method method, Class clazz) {
		System.out.println("调用matches(method,clazz)对"+clazz.getName()+"."+method.getName()+"做静态检查.");
		return "greetTo".equals(method.getName());
	}
	public boolean matches(Method method, Class clazz, Object[] args) {
		System.out.println("调用matches(method,clazz)对"+clazz.getName()+"."+method.getName()+"做动态检查.");
		String clientName = (String) args[0];
		return specialClientList.contains(clientName);
	}

}

GreetingDynamicPointcut类既有用于静态切点检查的方法,又有用于动态切点检查的方法。因为动态切点检查会对性能造成很大的影响,所以在创建代理时会对目标类的每个连接点使用静态切点检查,如果仅通过静态切点检查就可以知道连接点是不匹配的,则运行时不在进行动态检查,如果静态切点检查是匹配的,则在运行时才进行动态切点检查。
配置如下:

<bean id="dynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="pointcut">
			<bean class="com.smart.advisor.GreetingDynamicPointcut" />
		</property>
		<property name="advice">
			<bean class="com.smart.advisor.GreetingBeforeAdvice" />
		</property>
	</bean>


	<bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="dynamicAdvisor" p:target-ref="waiterTarget"
		p:proxyTargetClass="true" />

编写一个测试类,进行测试

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.testng.Assert.*;
import org.testng.annotations.*;
public class DynamicAdvisorTest {

	@Test
	public void dynamic() {
		String configPath = "com/smart/advisor/beans.xml";
		ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
		Waiter waiter = (Waiter) ctx.getBean("waiter2");		
		waiter.serveTo("Peter");
		waiter.greetTo("Peter");		
		waiter.serveTo("Peter");
		waiter.greetTo("John");
	}
}

运行以上代码,输出台输出信息如下:
在这里插入图片描述
从运行结果可以看出,Spring在创建代理织入切面时,对目标类中的所有方法进行静态切点检查,在生成织入切面的代理对象之后,第一次调用类时会进行一次静态切点检查,如果匹配,在之后的检查中就不在执行静态切点检查。
在将GreetingDynamicPointcut类的getClassFilter()和matches(Method method, Class clazz)方法注释掉,将得到以下输出信息
在这里插入图片描述
每次调用代理对象的任何一个方法,都会执行动态切点检查,这将导致很大的性能问题。
流程切面
Spring的流程切面由DefaultPointcutAdvisior和ControlFlowPointcut实现。流程切点代表由某个方法直接或间接发起调用的其他方法。如下实例,假设通过一个WaiterDelegate类代理Waiter所有方法。

public class WaiterDelegate {
	private Waiter waiter;
	public void service(String clientName) {
		waiter.greetTo(clientName);
		waiter.serveTo(clientName);
	}
	public void setWaiter(Waiter waiter) {
		this.waiter = waiter;
	}
}

如果希望所有由WaiterDelegate#service()方法发起调用的其他方法都织入增强,就必须使用流程切面来完成目标。接下来使用DefaultPointcutAdvisior配置一个流程切面来完成这一需求。

<bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
		<constructor-arg type="java.lang.Class"
			value="com.smart.advisor.WaiterDelegate" />
		<constructor-arg type="java.lang.String" value="service" />
	</bean>
	<bean id="controlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
		p:pointcut-ref="controlFlowPointcut" p:advice-ref="greetingAdvice" />
	<bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="controlFlowAdvisor" p:target-ref="waiterTarget"
		p:proxyTargetClass="true" />

接下来进行流程切面的测试

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.testng.Assert.*;
import org.testng.annotations.*;
public class ControlFlowAdvisorTest {

	@Test
	public void control() {
		String configPath = "com/smart/advisor/beans.xml";
		ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
		Waiter waiter = (Waiter) ctx.getBean("waiter3");
		WaiterDelegate wd = new WaiterDelegate();
        wd.setWaiter(waiter);
		waiter.serveTo("Peter");
		waiter.greetTo("Peter");
		wd.service("Peter");
	}
}

其输出信息如下
在这里插入图片描述
复合切点切面
ComposablePointcut可以将多个切点以并集或交集的方式组合起来,提供了切点之间的复合运算的功能。
ComposablePointcut提供了三个交集运算方法
ComposablePointcut intersection(ClassFilter classFilter) 将复合切点和一个ClassFilter对象进行交集运算,得到一个结果复合切点。
ComposablePointcut intersection(MethodMatcher matcher)
ComposablePointcut intersection(MethodMatcher matcher)
ComposablePointcut提供了两个并集运算方法
ComposablePointcut union(ClassFilter classFilter)
ComposablePointcut union(MethodMatcher matcher)
ComposablePointcut中没有提供直接对两个切点进行交并集运算的方法,可以使用Spring提供的org.springframework.aop.support.Pointcuts工具类。
Pointcut intersection(Pointcut a, Pointcut b)
Pointcut union(Pointcut a, Pointcut b)
首先通过ComposablePointcut创建一个流程切点和方法名切点的相交切点。

import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.ControlFlowPointcut;
import org.springframework.aop.support.NameMatchMethodPointcut;

public class GreetingComposablePointcut {
   public Pointcut getIntersectionPointcut(){
	   ComposablePointcut cp = new ComposablePointcut();
	   Pointcut pt1 = new ControlFlowPointcut(WaiterDelegate.class,"service");
	   NameMatchMethodPointcut pt2 = new NameMatchMethodPointcut();
	   pt2.addMethodName("greetTo");
	   return cp.intersection(pt1).intersection((Pointcut)pt2);    
   }
}
<bean id="gcp" class="com.smart.advisor.GreetingComposablePointcut" />
<bean id="composableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
		p:pointcut="#{gcp.intersectionPointcut}" p:advice-ref="greetingAdvice" />
<bean id="waiter4" class="org.springframework.aop.framework.ProxyFactoryBean"
	p:interceptorNames="composableAdvisor" p:target-ref="waiterTarget"
	p:proxyTargetClass="true" />

测试代码

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.testng.Assert.*;
import org.testng.annotations.*;
public class ComposableAdvisorTest {

	@Test
	public void composable(){
		String configPath = "com/smart/advisor/beans.xml";
		ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
		Waiter waiter = (Waiter) ctx.getBean("waiter4");
		WaiterDelegate wd = new WaiterDelegate();
        wd.setWaiter(waiter);
		waiter.serveTo("Peter");
		waiter.greetTo("Peter");
		wd.service("Peter");
	}
}

其输出结果如下
在这里插入图片描述
引介切面
首先是引介切面的类继承关系图
在这里插入图片描述
在IntroductionInfo接口描述了目标类需要实现的新接口,在IntroductionAdvisior中,它仅有一个类过滤器ClassFilter,而没有MethodMatcher,这是因为引介切面是类级别的。
DefaultIntroductionAdvisior为引介切面最常用的实现类。
引介切面配置如下:

public interface Testable {
  void test();
}
public interface Monitorable {
   void setMonitorActive(boolean active);
}
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class ControllablePerformaceMonitor
		extends
			DelegatingIntroductionInterceptor implements Monitorable, Testable {
	private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();
	public void setMonitorActive(boolean active) {
		MonitorStatusMap.set(active);
	}
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object obj = null;
		if (MonitorStatusMap.get() != null && MonitorStatusMap.get()) {
			PerformanceMonitor.begin(mi.getClass().getName() + "."
					+ mi.getMethod().getName());
			obj = super.invoke(mi);
			PerformanceMonitor.end();
		} else {
			obj = super.invoke(mi);
		}
		return obj;
	}
	public void test() {
		// TODO Auto-generated method stub
		System.out.println("dd");
	}
}
<bean id="introduceAdvisor"
		class="org.springframework.aop.support.DefaultIntroductionAdvisor">
		<constructor-arg>
			<bean class="com.smart.introduce.ControllablePerformaceMonitor" />
		</constructor-arg>
	</bean>
	<bean id="forumServiceTarget" class="com.smart.introduce.ForumService" />
	<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
	      p:interceptorNames="introduceAdvisor"
	      p:target-ref="forumServiceTarget"
	      p:proxyTargetClass="true"/>

五、通过AspectJ实现切面
在前面分别使用Pointcut和Advice接口描述切点和增强,并用Advisior整合二者描述切面。AspectJ则采用注解来描述切点,增强,二者只是描述方式不同,但是其本质是一样的。
AspectJ语法基础
        切点表达式函数
在Spring中支持9个@AspectJ切点表达式函数,他们用不同的方式描述目标类的连接点,根据描述对象的不同,可以大致分为4中类型

  • 方法切点函数:通过描述目标类方法的信息定义连接点。
  • 方法入参切点函数:通过描述目标类方法入参的信息定义连接点。
  • 目标类切点函数:通过描述目标类类型的信息定义连接点。
  • 代理类切点函数:通过描述目标类的代理类的信息定义连接点。
    在这里插入图片描述
    在函数入参中使用通配符
    在@AspectJ中支持3种通配符
    *:匹配任意字符,但它只能匹配上下文中的一个元素
    . . : 匹配任意字符,可以匹配上下文种多个元素,但在表示类时,必须和 *联合使用,而在表示入参时则单独使用。
    +:必须按类型匹配指定类的所有类,必须跟在类名后面,如com.demo.Car+,继承或扩展指定类的所有类,同时还包括指定类本身。
    AspectJ函数按其是否支持通配符及支持程度,可以分为以下3类
    在这里插入图片描述

六、基于schema配置切面
在基于schema的切面配置中,有两种配置方式。
一种是基本的Aspect配置, 其例子如下
在这里插入图片描述
这样就配置好了一个简单的切面,在< aop:config>中可以定义多个切面。< aop:aspect>
一个切面中可以定义多个增强
。在①处引用的Bean为增强方法所在的类。
通过< aop:before>定义了一个增强,pointcut定义一个切点,method为增强类中具体的增强方法。
当proxy-target-class设置为true时,切面均使用CGLib动态代理技术,当设置为false时,使用java动态代理技术。
也可以配置命名切点,示例如下。
在这里插入图片描述
基于schema的切面配置中,绑定连接点信息与AspectJ类似。

  • 所有的增强方法第一个参数可以声明为JoinPoint,访问连接点信息。
  • < aop:after-returning> 可以通过returning属性绑定连接点方法的返回值。< aop:after-throwing>通过throwing方法绑定连接点方法所抛出的异常。
    在这里插入图片描述
    在这里插入图片描述
    另一种是基于Advisior的配置。Advisior是切点和增强的复合体。
    在这里插入图片描述
内容概要:本文提出了一种基于改进扩散模型的高海拔地区新能源高波动出力场景生成方法,并提供了完整的Python代码实现。该方法针对高海拔地区风能、光伏等新能源出力波动剧烈、不确定性高的特点,通过优化扩散模型的结构与训练策略,有效捕捉历史数据的概率分布特征与时序相关性,从而生成高质量、多样化的出力场景。文中详细阐述了模型的数学推导、网络架构设计、损失函数优化及采样算法改进,并通过实验证明其在拟合精度、场景多样性与稳定性方面优于传统生成模型,为电力系统在高比例新能源接入下的规划、调度与风险评估提供了可靠的场景输入支持。; 适合人群:具备一定Python编程能力和机器学习基础,从事新能源发电预测、电力系统分析、智能优化、场景生成等方向研究的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①用于高海拔地区风电、光伏出力的不确定性建模与多场景生成;②支撑含高渗透率新能源的电力系统随机优化调度、鲁棒决策与风险评估;③为相关学术研究、论文复现与算法改进提供可运行的技术方案与代码基础; 阅读建议:建议读者结合所提供的完整资源(代码、数据集、说明文档)进行实践操作,重点关注扩散模型的前向加噪与反向去噪过程的设计细节,以及如何将其适配于新能源时序数据的生成任务,通过参数调优与对比实验深入理解模型的生成机制与性能边界。
内容概要:本文围绕基于静态约束法的配电网电动汽车接入容量评估展开研究,提出了一种在新型电力系统背景下评估主动配电网对电动汽车承载能力的方法。研究通过构建数学模型,结合潮流计算与关键约束条件(如电压越限、线路过载等),量化分析配电网可承受的最大电动汽车充电负荷容量,旨在识别规模化电动汽车接入带来的潜在运行风险,并为电网规划与运行提供科学依据。文中配套提供了完整的Matlab代码实现,便于仿真验证与结果复现。此外,该研究与分布式光伏承载力评估、电动汽车可调能力分析等方向形成技术联动,展现了多主题协同的研究体系。; 适合人群:具备电力系统分析基础理论知识及Matlab编程能力的高校研究生、科研机构研究人员,以及从事新能源并网、智能配电网规划与运行等相关领域的工程技术人员。; 使用场景及目标:①用于学术研究中的模型复现与论文撰写支撑;②评估实际配电网中电动汽车大规模接入的可行性与安全边界,指导充电基础设施布局;③作为高校教学案例,帮助学生深入理解电网承载力评估的核心原理、建模方法与仿真技术; 阅读建议:建议结合文中提及的相关研究方向(如二阶锥规划、多面体聚合方法等)进行对比学习,充分利用所提供的Matlab代码与网盘资料开展仿真实验,重点关注约束条件的设定逻辑与潮流计算模块的实现细节,以深化对评估模型机理与工程应用价值的理解。
内容概要:本文围绕“考虑隐私保护的分布式联邦学习电力负荷预测研究”展开,提出了一种基于Python实现的联邦学习框架,旨在解决居民或行业电力负荷预测中用户电表数据隐私泄露的风险。该研究通过构建分布式机器学习模型,使各参与方在不共享原始数据的前提下协同训练全局模型,有效实现了数据“可用不可见”。文中详细阐述了联邦学习的整体架构设计、本地模型训练流程、参数加密传输与安全聚合机制,并结合差分隐私等技术进一步增强系统的隐私保护能力。同时,研究利用真实电力负荷数据集进行了实验验证,展示了方法在预测精度与隐私保障之间的良好平衡,并提供了完整的代码实例与复现指南,便于后续研究与应用拓展。; 适合人群:具备一定机器学习基础和电力系统背景知识,从事智慧能源、隐私计算或人工智能相关方向研究的研究生、科研人员及工程技术人员。; 使用场景及目标:① 实现跨区域、跨主体的电力负荷协同预测,打破数据孤岛;② 在确保用户用电数据隐私安全的前提下提升负荷预测准确性;③ 推动联邦学习在智能电网、需求响应、虚拟电厂等场景中的实际部署与应用。; 阅读建议:建议结合文中提供的Python代码与网盘资料进行动手实践,重点关注联邦学习的通信轮次设计、模型聚合算法(如FedAvg)的实现细节以及差分隐私噪声添加策略,深入理解其对模型性能与隐私强度的影响,为进一步优化与创新奠定基础。
VDA_Band_19.1_3rd edition_2026 English Inspection of Technical Cleanliness 内容概要:本文档为德国汽车工业协会(VDA)发布的第三版《技术清洁度检验:功能相关汽车部件的颗粒污染检测》(VDA 19.1),系统规范了汽车行业中零部件技术清洁度的检测方法与流程。文件涵盖从取样、提取、过滤到分析的全流程标准化操作,重点更新了干法提取(如 Stamp Test 和刷吸法)、小于50µm颗粒的检测、光学子系统和SEM/EDX标准分析方法,并引入统一材料分类体系以提升结果可比性。同时明确了“标准分析”与“自由检验”的区别,前者用于高兼容性检测,后者允许客户与供应商协商定制参数。文档还强化了对非可测组件的技术清洁保障、测量不确定度评估及方法验证的要求,并提供了多个实际案例支持应用落地。; 适合人群:适用于汽车制造业中从事质量控制、工艺开发、供应商管理及相关检测实验室的技术人员和管理人员,尤其适合具备一定质量管理或洁净度检测基础的专业人员。; 使用场景及目标:①用于制定和执行零部件清洁度检测标准;②指导 incoming/outgoing 检验及生产过程监控;③支持失效分析与质量改进项目;④作为企业内部审核和技术交流的依据; 阅读建议:建议结合VDA 19.2及其他相关标准配套使用,重点关注各章节中的起始参数设定、方法选择逻辑及附录中的检查表示例,在实际操作中同步开展方法验证与人员培训,确保检测结果的有效性和可追溯性。
内容概要:本研究聚焦于电动汽车(EV)作为灵活可调资源的能力评估,提出了一种基于多面体聚合与闵可夫斯基和的数学建模方法,用以精确刻画大规模电动汽车集群的可调能力范围。通过将单辆电动汽车的充放电行为抽象为几何空间中的多面体可行域,并利用闵可夫斯基和实现对群体可行域的高效聚合,从而构建出能够反映整体调节潜力的统一数学表达。该方法在Matlab平台上实现了完整的仿真代码,支持对不同场景下电动汽车集群的上、下调能力进行量化评估,为电网调度、需求响应及电力市场机制设计提供了理论依据与工具支撑。; 适合人群:具备电力系统分析、优化理论及Matlab编程基础的研究生、科研人员及从事新能源、智能电网相关工作的工程师。; 使用场景及目标:①用于评估大规模电动汽车接入背景下系统的灵活性资源潜力;②支撑含高比例可再生能源的电力系统调度与规划决策;③为需求响应项目中EV聚合商参与电力市场提供能力申报的技术手段;④作为教学案例帮助理解集合运算在电力系统中的应用。; 阅读建议:学习者应结合Matlab代码深入理解多面体建模与闵可夫斯基和的实现细节,建议从单车模型入手逐步过渡到集群聚合,并尝试调整参数(如数量、SOC分布、功率限制)观察聚合结果的变化,以增强对模型特性的掌握。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值