`

spring-aop-ProxyFactory 源码分析

阅读更多
spring 提供的编程式aop实现,即通过 ProxyFactory类完成的。
另外AnnotationAwareAspectJAutoProxyCreator  BeanNameAutoProxyCreator  DefaultAdvisorAutoProxyCreator 等自动aop代理创建器都是通过在其父类AbstractAutoProxyCreator中通过ProxyFactory 来实现aop逻辑的植入。所以理解ProxyFactory 的使用对理解spring aop 至关重要。

分析ProxyFactory 可以从两条线来分析:
1、代理对象的创建
2、method的调用以及拦截器(Advice)的织入。


使用方式:
业务逻辑
public class LoginServiceImpl implements LoginService {
	public boolean login(User user) {
		System.out.println(user);
		if (user == null) {
			return false;
		} else if (user.getUsername() == "xinchun.wang" && user.getPassword() == "123456") {
			return true;
		}
		return false;
	}
}

addvice增强
public class AfterAdvice1 implements AfterReturningAdvice{

	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("AfterAdvice1.afterReturning() execute ");
	}
}
//
public class AfterAdvice2 implements AfterReturningAdvice{

	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("AfterAdvice2.afterReturning() execute ");
		
	}
}

public class BeforeAdvice1 implements MethodBeforeAdvice{
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("BeforeAdvice1.before() execute ");
	}
}

public class BeforeAdvice2 implements MethodBeforeAdvice{

	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("BeforeAdvice2.before() execute ");
	}
   
}

测试用例:
@Test
	public void proxyLoginTest() {
		ProxyFactory factory = new ProxyFactory();
		factory.addAdvice(new BeforeAdvice1());
		factory.addAdvice(new BeforeAdvice2());
		factory.addAdvice(new AfterAdvice1());
		factory.addAdvice(new AfterAdvice2());
		LoginService target = new LoginServiceImpl();
		factory.setTarget(target);
		factory.setProxyTargetClass(false);
		factory.setInterfaces(new Class[]{LoginService.class});
		
		LoginService service = (LoginService)factory.getProxy();
		System.out.println(service.login(new User("xinchun.wang","123456")));
	}

输出:
BeforeAdvice1.before() execute
BeforeAdvice2.before() execute
User [username=admin, password=123456, open=false]
AfterAdvice2.afterReturning() execute
AfterAdvice1.afterReturning() execute
true

数据结构:
ProxyConfig: 代理的基础配置属性
AdvisedSupport:提供基础的Advice的包装,Advisor 列表的维护,TargetSource 对象的维护,以及Interceptor 数据结构的解析和封装。

ProxyCreatorSupport:代理工厂的基类,主要负责代理对象的生成。
ProxyFactory:最常用的代理工厂应用,包含一些静态工厂方法,以及代理对象生成的方法。

public class ProxyFactory extends ProxyCreatorSupport {
//指定待实现接口和拦截器
   public ProxyFactory(Class proxyInterface, Interceptor interceptor) {
		addInterface(proxyInterface); //JDK代理需要接口
		addAdvice(interceptor);//添加增强逻辑
	}
}

//通过指定一个目标对象,构造ProxyFactory,可以继续通过addAdvice(interceptor);添加拦截器
public ProxyFactory(Object target) {
		Assert.notNull(target, "Target object must not be null");
		setInterfaces(ClassUtils.getAllInterfaces(target));
		setTarget(target);
	}

//生成代理对象,createAopProxy 在ProxyCreatorSupport 中实现
public Object getProxy() {
		return createAopProxy().getProxy();
	}

}


代理创建分析线
ProxyCreatorSupport 提供的createAopProxy() 提供了aopProxy的生成

/** 代理工厂的基类,提供了对 AopProxyFactory 的包装*/
public class ProxyCreatorSupport extends AdvisedSupport {
  //代理工厂,默认实现 DefaultAopProxyFactory 提供了 JdkDynamicAopProxy 和 Cglib2AopProxy 的生成
	private AopProxyFactory aopProxyFactory; 
  //aop配置的监听器
	private List<AdvisedSupportListener> listeners = new LinkedList<AdvisedSupportListener>();

	/** Set to true when the first AOP proxy has been created */
	private boolean active = false;

	/**
	 * 默认实现,指定DefaultAopProxyFactory 为默认aop代理生成工厂
	 */
	public ProxyCreatorSupport() {
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}

	/**
	 * 同上自定义一个AopProxyFactory,来实现aop代理对象的生成
	 */
	public ProxyCreatorSupport(AopProxyFactory aopProxyFactory) {
		Assert.notNull(aopProxyFactory, "AopProxyFactory must not be null");
		this.aopProxyFactory = aopProxyFactory;
	}
	/**
	 *留给子类调用的代理生成,此次是aop代理生成的入口
	 */
	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) { //第一次激活的时候,调用相关的监听器
			activate();
		}
		return getAopProxyFactory().createAopProxy(this); //通过aop代理工厂 生成AopProxy
	}

}

代理创建分析线 DefaultAopProxyFactory 的 createAopProxy 方法
/** 默认的代理工厂实现
当 optimize =true或proxyTargetClass=ture 或 no proxy interfaces 指定,使用CGLIB 来生成代理,否则jdk代理
*/
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	/** 检查CGLIB2 相关类是否存在 */
	private static final boolean cglibAvailable =
			ClassUtils.isPresent("net.sf.cglib.proxy.Enhancer", DefaultAopProxyFactory.class.getClassLoader());


	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		//optimize =true或proxyTargetClass=ture 或 no proxy interfaces 指定,使用CGLIB 来生成代理
		//optimize 做优化,早期jdk的代理的生成相当慢,不过现在基本差异不大
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class targetClass = config.getTargetClass();
			if (targetClass == null) { //被代理的对象不能为空
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface()) { //虽然符合以上要求,但是如果代理对象是借口,那么继续使用jdk
				return new JdkDynamicAopProxy(config);
			}
			if (!cglibAvailable) {
				throw new AopConfigException(
						"Cannot proxy target class because CGLIB2 is not available. " +
						"Add CGLIB to the class path or specify proxy interfaces.");
			}
			return CglibProxyFactory.createCglibProxy(config); // Cglib2 代理
		}
		else {
			return new JdkDynamicAopProxy(config); //jdk 代理
		}
	}

	/**
	 * 判断是否有接口
	 */
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class[] interfaces = config.getProxiedInterfaces();
		return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
	}

	/**
	 * 创建Cglib2AopProxy
	 */
	private static class CglibProxyFactory {
		public static AopProxy createCglibProxy(AdvisedSupport advisedSupport) {
			return new Cglib2AopProxy(advisedSupport);
		}
	}
}


代理创建分析线 举例 JdkDynamicAopProxy 的getProxy 方法
/**
 * 基于JDK动态代理 的Aop代理实现
   通过JDK代理的方法调用 只对接口中的方法做拦截
   即使真实对象不是线程安全的,通过JdkDynamicAopProxy 产生的对象依然是线程安全的。
 */
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

	private static final long serialVersionUID = 5531744639992436476L;

	/** We use a static Log to avoid serialization issues */
	private static Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);

	/** aop的配置信息(增强逻辑,真是对象,切点信息) */
	private final AdvisedSupport advised;

	/** 代理接口是否有equals方法
	 */
	private boolean equalsDefined;

	/** 代理借口是否有hashCode方法
	 */
	private boolean hashCodeDefined;


	public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
	}

  /** 获取代理*/
	public Object getProxy() {
		return getProxy(ClassUtils.getDefaultClassLoader());
	}

/**  至此方法结束,通过jdk生成代理对象已经完成*/
	public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); //找到所有借口
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); //生成代理
	}

	/**
	 * 检查是否定义了hashCode  equals 方法 
	 */
	private void findDefinedEqualsAndHashCodeMethods(Class[] proxiedInterfaces) {
		for (Class proxiedInterface : proxiedInterfaces) {
			Method[] methods = proxiedInterface.getDeclaredMethods();
			for (Method method : methods) {
				if (AopUtils.isEqualsMethod(method)) {
					this.equalsDefined = true;
				}
				if (AopUtils.isHashCodeMethod(method)) {
					this.hashCodeDefined = true;
				}
				if (this.equalsDefined && this.hashCodeDefined) {
					return;
				}
			}
		}
	}

	/**
	 * 这里是代理对象调用,也是jdk代理 实现的核心逻辑
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Class targetClass = null;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { //如果代理的是equlas 方法
				return equals(args[0]);
			}
			if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { //如果代理的是hashCode方法
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) { // 是否允许把当前代理放到AopContext中,这样可以保存在ThreadLocal中,在代码里使用AopContext.currentProxy() 获取当前代理
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// 获取目标对象以及Class类型
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}

			// 根据Method 和 targetClass 获取对应的拦截器(Advice增强封装) 这里是获取拦截逻辑的地方。(MethodMatcher 和 ClassFilter 在此处做匹配)
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// 如果没有配置,或者没有匹配到任何方法,那么直接调用当前实例的方法即可
			if (chain.isEmpty()) {
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
			}
			else {
				// ReflectiveMethodInvocation 类封装了 增强和实例方法的调用
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				//aop的增强的植入 精华全在于此
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				retVal = proxy;
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				AopContext.setCurrentProxy(oldProxy); //恢复currentProxy
			}
		}
	}

}


代理方法调用分析线
JdkDynamicAopProxy 实现InvocationHandler,其方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 会拦截所有通过代理调用的方法(如果对此不清楚,建议了解jdk的动态代理的实现)因此invoke就是调用的入口

基于以上分析,先看看拦截器对象的获取。 AdvisedSupport 的 getInterceptorsAndDynamicInterceptionAdvice 方法
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}

从上面代码可以看出,是做了缓存,如果缓存不存在,通过 AdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice 来获取。 注意 这里把拦截器的获取委托的同时,仅仅提供了缓存功能,其他功能都进行了委托。

代理方法调用分析线 -拦截器的获取
/** 此类的实现的唯一功能就是从Advised中,根据method 和 targetClass 实现拦截器的获取*/
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, Class targetClass) {

		List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
		//判断是否有引介增强
		boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
		//AdvisorAdapterRegistry 是对advice 的包装为MethodInterceptor 工具
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		for (Advisor advisor : config.getAdvisors()) {
			if (advisor instanceof PointcutAdvisor) { //如果是PointcutAdvisor,那么要对方法和类做匹配
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { //如果类匹配
				  // registry.getInterceptors(advisor) 这句话就是对Advice ->MethodInterceptor 包装
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { //如果方法也匹配
						if (mm.isRuntime()) { //如果是运行时判断,会考虑参数等因素
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else { //不是运行时,直接添加
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) { //引介增强
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { //引介增强只需匹配类,即可
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else { //如果不是PointcutAdvisor 也不是 IntroductionAdvisor,那么直接包装,默认是匹配的
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		return interceptorList;
	}

	/**
	 * 判断targetClass 是否匹配Advised中的任意一个Advisor
	 */
	private static boolean hasMatchingIntroductions(Advised config, Class targetClass) {
		for (int i = 0; i < config.getAdvisors().length; i++) {
			Advisor advisor = config.getAdvisors()[i];
			if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (ia.getClassFilter().matches(targetClass)) {
					return true;
				}
			}
		}
		return false;
	}

}

代理方法调用分析线 AdvisorAdapterRegistry 通过getInterceptors 对Advisor 包装,返回MethodInterceptor 的逻辑。
DefaultAdvisorAdapterRegistry 类这个接口的默认实现
/** 对advice 的包装为MethodInterceptor 功能*/
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
	private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
	/**
	 * 构造方法中默认注册最常用的三个Advice的适配器
	 */
	public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}

  //把advice 包装成Advisor
	public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
		if (adviceObject instanceof Advisor) {
			return (Advisor) adviceObject;
		}
		if (!(adviceObject instanceof Advice)) { //如果不是advice ,直接抛出异常
			throw new UnknownAdviceTypeException(adviceObject);
		}
		Advice advice = (Advice) adviceObject;
		if (advice instanceof MethodInterceptor) { //如果环绕拦截器,那么通过DefaultPointcutAdvisor包装
			return new DefaultPointcutAdvisor(advice);
		}
		for (AdvisorAdapter adapter : this.adapters) { //通过构造方法中的适配器来判断是否支持
			// Check that it is supported.
			if (adapter.supportsAdvice(advice)) {
				return new DefaultPointcutAdvisor(advice);
			}
		}
		throw new UnknownAdviceTypeException(advice);
	}

  //把advisor 包装为MethodInterceptor 列表,因为advisor 的Advice可能实现了MethodBeforeAdvice 同时也实现了 AfterReturningAdvice
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
	}

	public void registerAdvisorAdapter(AdvisorAdapter adapter) { //预留了扩展适配器的方法
		this.adapters.add(adapter);
	}
}


代理方法调用分析线 ReflectiveMethodInvocation.proceed() 方法的调用,这里拦截增强逻辑植入的地方。
public Object proceed() throws Throwable {
		//	我们从第一个currentInterceptorIndex = -1开始,如果currentInterceptorIndex 那么拦截器已经调用完,这时候调用真实的业务方法
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

    //从第一个拦截器开始调用
		Object interceptorOrInterceptionAdvice =
		    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		    // 如果是动态匹配
		  if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			InterceptorAndDynamicMethodMatcher dm =
			    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			    //动态匹配时,会考虑到参数,如果匹配就调用
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this); 
			}
			else {
				//如果动态匹配失败,那么继续进行下一个拦截器调用
				return proceed();
			}
		}
		else {
			// 如果是静态的,那么已经在构造ReflectiveMethodInvocation时,过滤了,都是匹配的拦截器,那么直接调用
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

  //实现思路很简单,就是method 在 target上进行反射调用
  protected Object invokeJoinpoint() throws Throwable {
		return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
	}


至此,调用分析已经完毕,但是似乎没有看到增强具体的逻辑,其实不然,这些拦截器是对advice封装,让我们看下这些对advice'的拦截器适配的实现。 这些逻辑的封装是在AdvisorAdapter 中的各个实现。
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof MethodBeforeAdvice);
	}
	public MethodInterceptor getInterceptor(Advisor advisor) {
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
		return new MethodBeforeAdviceInterceptor(advice); //如果是MethodBeforeAdvice,那么使用MethodBeforeAdviceInterceptor 进行适配
	}

}

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}

	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); //前置增强的调用,然后继续向下调用
		return mi.proceed();
	}

}

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof AfterReturningAdvice);
	}
	public MethodInterceptor getInterceptor(Advisor advisor) {
		AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
		return new AfterReturningAdviceInterceptor(advice);
	}

}

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;
	public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();//先让其他方法调用完,然后才调用自己的后置增强
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

至此分析完毕,一个简单的spring aop实现ProxyFactory 大致轮廓就是如此!

另外:如果你能清楚的理解下面的输出顺序,并且在随意更改advice添加顺序的情况下,你都能清楚预测出输出顺序,ok,你明白了AfterReturningAdviceInterceptor和MethodBeforeAdviceInterceptor 的invoke方法执行流程啦~

BeforeAdvice1.before() execute
BeforeAdvice2.before() execute
User [username=admin, password=123456, open=false]
AfterAdvice2.afterReturning() execute
AfterAdvice1.afterReturning() execute
3
0
分享到:
评论
1 楼 superhero100 2015-11-06  
good! mark!

相关推荐

    spring-aop.jar各个版本

    spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...

    开发工具 spring-aop-4.3.6.RELEASE

    开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE开发工具 spring-aop-4.3.6.RELEASE...

    spring-aop-5.2.0.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.2.0.RELEASE.jar; 赠送原API文档:spring-aop-5.2.0.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.2.0.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.2.0.RELEASE.pom;...

    spring-aop-5.0.8.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.0.8.RELEASE.jar; 赠送原API文档:spring-aop-5.0.8.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.0.8.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.0.8.RELEASE.pom;...

    spring-aop-jar

    "spring-aop-jar"这个主题涉及到Spring框架中的核心组件之一——Spring AOP。这里我们将深入探讨Spring AOP、相关jar文件以及它们在实际开发中的作用。 首先,我们来看一下提供的文件: 1. aopalliance.jar:这是一...

    spring-aop-6.0.2.jar

    spring-aop-6.0.2.jar

    spring-aop-5.0.10.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.0.10.RELEASE.jar; 赠送原API文档:spring-aop-5.0.10.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.0.10.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.0.10.RELEASE....

    spring-aop-5.3.10-API文档-中文版.zip

    赠送jar包:spring-aop-5.3.10.jar; 赠送原API文档:spring-aop-5.3.10-javadoc.jar; 赠送源代码:spring-aop-5.3.10-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.3.10.pom; 包含翻译后的API文档:spring...

    spring,spring-aop-5.3.22.jar+aop+IDEA本地包

    spring-aop-5.3.22.jar Spring AOP provides an Alliance-compliant aspect-oriented programming implementation allowing you to define method interceptors and pointcuts to cleanly decouple code that ...

    spring-aop-5.3.12-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.3.12.jar; 赠送原API文档:spring-aop-5.3.12-javadoc.jar; 赠送源代码:spring-aop-5.3.12-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.3.12.pom; 包含翻译后的API文档:spring...

    spring-aop-5.2.0.RELEASE.jar

    spring-aop-5.2.0.RELEASE

    spring-aop-4.3.20.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-4.3.20.RELEASE.jar; 赠送原API文档:spring-aop-4.3.20.RELEASE-javadoc.jar; 赠送源代码:spring-aop-4.3.20.RELEASE-sources.jar; 包含翻译后的API文档:spring-aop-4.3.20.RELEASE-...

    spring-aop-5.2.15.RELEASE-API文档-中文版.zip

    赠送jar包:spring-aop-5.2.15.RELEASE.jar; 赠送原API文档:spring-aop-5.2.15.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.2.15.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.2.15.RELEASE....

    spring-aop-3.2.5.RELEASE.jar ;spring-aop-3.2.5.jar

    spring-aop-3.2.5.RELEASE.jar

    spring-aop-3.2.0.RELEASE.jar

    spring-aop-3.2.0.RELEASE.jar,一个Spring中AOP的jar包

    spring-aop-5.1.3.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-aop-5.1.3.RELEASE.jar; 赠送原API文档:spring-aop-5.1.3.RELEASE-javadoc.jar; 赠送源代码:spring-aop-5.1.3.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-aop-5.1.3.RELEASE.pom;...

    spring-aop-4.3.20.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-aop-4.3.20.RELEASE.jar 赠送原API文档:spring-aop-4.3.20.RELEASE-javadoc.jar 赠送源代码:spring-aop-4.3.20.RELEASE-sources.jar 包含翻译后的API文档:spring-aop-4.3.20.RELEASE-...

    spring-aop-4.0.4.RELEASE

    spring-aop-4.0.4.RELEASE 的jar包,亲测可用。。。。

    spring-aop-5.0.4.RELEASE.jar

    spring-aop-5.0.4.RELEASE.jar。

    spring-aop-5.1.0.RELEASE.jar

    spring-**core**-4.3.6.RELEASE.jar :包含spring框架基本的核心工具类,spring其他组件都要用到这个包里的类,其他组件的基本核心 spring-**beans**-4.3.6.RELEASE.jar:所有应用都要用到的jar包,它包含访问配置...

Global site tag (gtag.js) - Google Analytics