提示:这里只对核心代码做讲解,如果你想彻底了解请打开你的编辑器定位到对应的源码上,一步一步跟着看相信你会有所收获的。
明词解释
链接点:在SpringAop中指的是方法.
目标对象:代理对象内部代理的那个对象,
目标方法:当前在目标对象上要执行的方法
通知:在链接点执行前、后、异常情况下要执行的代码,SpringAop中有前置通知、后置通知、异常通知、环绕通知。
拦截器:将通知适配成MethodInteceptor后代理通知的执行。你可以把它理解为通知
Pointcut
根据名字就知道它表示的是一个切入点。
ClassFilter 匹配要切入的类
MethodMatcher 匹配要切入的方法
以上三个接口中都有个属性TRUE表示自身接口的一个默认实现,均返回true。MethodMatcher.isRuntime方法除外,此方法表示是否需要在程序运行的时候动态决定是否切入某个方法。如(ControlFlowPointcut根据当前线程的堆栈信息来决定是否切入某方法的)
Advice
这个接口的实现类代表着你的通知(前置通知,后置通知,异常通知,环绕通知等)
Advisor
这个接口表示一个切面,它持有Advice的引用,它的子接口PointcutAdvisor持有Pointcut的引用。你会不会这么觉得:这个接口的实现类会根据pointCut来决定是否调其advice执行相应的通知.(差不多是这样的,但不是它的实现类去做这个事,这个接口仅仅负责收集配置信息,做这件事的是AdvisedSupport类的getInterceptorsAndDynamicInterceptionAdvice方法,稍后会提)
Advised
这个接口支持多个Advisor或Advice、加入了需要代理的源对象(TargetSource)、需要代理的接口等(getProxiedInterfaces介个方法).这个接口的职责是将切面、目标对象、需要代理的接口组织起来。它的实现类是AdvisedSupport。
AdvisedSupport
它实现了Advised接口。它可以动态添加,修改,删除通知和动态切换目标对象,即使代理对象已经创建。这个类有两个地方需要注意。
1、所有addAdvice方法的重载方法都会将参数Advice转成包装成Advisor并调用addAdvisor方法.
public void addAdvice(int pos, Advice advice) throws AopConfigException { Assert.notNull(advice, "Advice must not be null"); if (advice instanceof IntroductionInfo) { //如果是一个引入通知,则将其包装成默认的实现引入切面 addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice)); } else if (advice instanceof DynamicIntroductionAdvice) { throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor"); } else { //创建默认切面实现 addAdvisor(pos, new DefaultPointcutAdvisor(advice)); } } //对所有Advisor的变化操作都会调用此方法,清空拦截器链缓存.(请参看要注意的第二点) protected void adviceChanged() { this.methodCache.clear(); }
DefaultPointcutAdvisor的构造方法
public DefaultPointcutAdvisor(Advice advice) { this(Pointcut.TRUE, advice); }
它将设置一个TRUE的切入点。意味着它可以切入任何类的任何方法.
2、getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass)方法
这个将会在目标类方法执行之前被调用,它返回匹配targetClasst和method的拦截器(其实就是通知【Advice】对象封装,利用Advisor的Pointcut属性去匹配适合的通知)
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { //创建一个缓存key MethodCacheKey cacheKey = new MethodCacheKey(method); //从缓存中取出拦截器链 List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { /* * 缓存中不存在则调用DefaultAdvisorChainFactory工厂类的getInterceptorsAndDynamicInterceptionAdvice方法获取 */ cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
DefaultAdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice方法
/** * 获取匹配targetClass与method的所有切面的通知 */ public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class targetClass) { List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); //下面这个适配器将的通知【Advice】包装成方法拦截器【MethodInterceptor】。【DefaultAdvisorAdapterRegistry】适配器的默认实现. AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; //判断此切面【advisor】是否匹配targetClass if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { //通过适配器将通知【Advice】包装成MethodInterceptor,这里为什么是个数组呢?因为一个通知类可能同时实现了前知通知【MethodBeforeAdvice】、后置通知【AfterReturningAdvice】、异常通知接口【ThrowsAdvice】,环绕通知【MethodInterceptor】,这里会将每个通知统一包装成MethodInterceptor MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); //是否匹配targetClass类的method方法 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) { //如果是引入切面的话则判断它是否适用于目标类,Spring中默认的引入切面实现是DefaultIntroductionAdvisor类,默认的引入通知是DelegatingIntroductionInterceptor它实现了MethodInterceptor接口 IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
DefaultAdvisorAdapterRegistry适配器代码
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3); /** * 在构造器中把3种适配器写死了,你应该能猜出这是三种神马适配器吧 */ 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)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); } /** * 将Advisor中的Advice接口适配成MethodInteceptor接口 */ 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) { //当前适配器是不是支持此Advice的适配工作 if (adapter.supportsAdvice(advice)) { //将Advice适配成MethodInterceptor interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } //将list转成数组返回. return interceptors.toArray(new MethodInterceptor[interceptors.size()]); } public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); } }
ProxyCreatorSupport
这个类继承自AdvisedSupport提供创建代理对象的支持类,默认情况下它是使用DefaultAopProxyFactory工厂类来创建代理的.它还有个功能就是在创建代理对象之前触发Listener.
protected final synchronized AopProxy createAopProxy() { if (!this.active) { //触发Listener. activate(); } return getAopProxyFactory().createAopProxy(this); }
DefaultAopProxyFactory
它是创建Aop代理工厂的默认实现,它会自动判断是否使用jdk的动态代理还是使用cglib的动态代理。
//当前类路径是不是能找到cglib相关的类(可以理解成cglib的jar包有没有被放到类路径) private static final boolean cglibAvailable = ClassUtils.isPresent("net.sf.cglib.proxy.Enhancer", DefaultAopProxyFactory.class.getClassLoader()); public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //启用了优化配置||启用了直接代理目标类模式||没有指定要代理的接口 则进入if. 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()) { 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."); } //返回创建cglib代理的工厂方法对象 return CglibProxyFactory.createCglibProxy(config); } else { //返回创建jdk代理的工厂方法对象 return new JdkDynamicAopProxy(config); } }
JdkDynamicAopProxy
它是一个动态代理类,实现了java.lang.reflect.InvocationHandler接口,使用JDK自带的动态代理机制代理targetClass。它实现了AopProxy接口的getProxy方法来返回代理对象。
public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } //得到需要代理的所有接口,在默认情况下AopProxyUtils会把SpringProxy和Advised两个接口添加到后面。SpringProxy是一个标记接口,它仅仅标记当前对象是不是由Spring生成的一个代理;Advised接口则是为了使得代理类可以动态操作其AOP通知.默认情况下所有的代理对象均可以转换成Advised接口操作其代理对象内部的Advised对象.(这其实就是一个引入的实现,关于引入请参看后面关于引入的实现);这个要注意了,不然在后面InvocationHandler的invoke方法中第3个if会感觉慕名奇妙 Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); //查询这些接口中是否有eauals,hashCode的实现,以区别于代理对象的equals,hashCode方法 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
下面是代理类最核心的地方
//java.lang.reflect.InvocationHandler接口的实现 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; //目标对象的包装类,通过AdvisedSupportr的setTarget方法设置的会被自动封闭成TargetSource的实现类SingletonTargetSource TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null; try { //被代理的接口中没有定义equals方法且当前方法是equals方法,则调用equals方法比较两代理对象所代理的接口、切面、目标对象是不是相等的。 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } //同上 if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); } //对Advised接口或子接口的中方法的调用不经过任何拦截器,直接委托给它内部维护Advised对象中的方法(此if块的目的是实现将advised对象引入代理对象),this.advised.opaque默认情况下是false(它只是一个开关选项,控制着代理对象是否可以操作advised.) if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { //调用advised的method方法 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; //是否将当前的代理对象做一个AOP框架暴露 if (this.advised.exposeProxy) { //把当前代理对象放入AopContext中(其内部使用ThreadLocal存着)并返回上下文中原来的代理对象,并且保留之前暴露设置的代理 oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } //得到目标对象 target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } //这个方法之前提到过,请上翻 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { //没有任何拦截器需要执行则直接执行目标对象的方法 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { //创建一个执行环境来处理拦截器和目标方法的执行(注意它的参数),这是一个递归的过程.后面再详细说明. invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); } //处理返回目标对象本身的情况.也许某些方法是返回this引用的,此时需要返回代理对象而不是目标对象. if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } return retVal; } finally { //也许你感觉finally中的代码不明白,那么可以看下介绍AdvisedSupport的红色字 if (target != null && !targetSource.isStatic()) { //如果此targetSource不是一个静态的targetSource,那么释放此target,默认的SingletonTargetSource.isStatic方法是为true的 targetSource.releaseTarget(target); } if (setProxyContext) { //还原之前的代理对象 AopContext.setCurrentProxy(oldProxy); } } }
ReflectiveMethodInvocation的核心方法
public Object proceed() throws Throwable { //currentInterceptorIndex默认等于-1的,它记录着当前执行到了哪个栏截器 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { //如果所有的拦截器都执行完了的话,则调用invokeJoinpoint方法去执行目标对象的目标方法 return invokeJoinpoint(); } //得到当前要执行的拦截器(拦截器是顺序执行的发现木有=.=) Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //下面判断当前拦截器是不是一个动态拦截器,之前有讲过 请上翻 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; //这里调用MethodMatcher类中带三个参数的matches方法 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { //匹配目标类的目标方法后执行此拦截器 return dm.interceptor.invoke(this); } else { //递归调用,下一个拦截器或目标类的方法. return proceed(); } } else { //调用拦截器的invoke方法并将this传递过去,这样拦截器里中的代码就有了是否继续执行的权限 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
引入
IntroductionAdvisor接口是引入切面的基本接口,它的默认实现是DefaultIntroductionAdvisor类,默认的引入通知是DelegatingIntroductionInterceptor它实现了MethodInterceptor接口。可以这样理解:spring其实就是通过一个特殊的MethodInteceptor来实现引入的。下面直接看这个拦截器的核心代码.
//delegate这个对象的方法将会引入到目标对象中,spring中只能进行接口的引入,这意味着delegate或其超类必需实现至少一个接口,在对目标类执行这些接口中的方法的时候spring会将其委托给delegate去执行,这样看上去就像是将一个类的方法(接口中的方法)动态赋予给目标类一样。 private Object delegate; public Object invoke(MethodInvocation mi) throws Throwable { //如果mi中执行的方法是delegate对象实现的接口中的方法 if (isMethodOnIntroducedInterface(mi)) { //将此方法的执行委托给delegate对象. Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments()); //处理返回this的情况 if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) { Object proxy = ((ProxyMethodInvocation) mi).getProxy(); if (mi.getMethod().getReturnType().isInstance(proxy)) { retVal = proxy; } } return retVal; } //执行目标方法 return doProceed(mi); }
举例Spring基于ProxyCreatorSupport做了一些扩展
1、ProxyFactory继承自ProxyCreatorSupport简化了aop的配置.例:
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();//创建一个默认的切面实现 advisor.setAdvice(myBeforeAdvice);//配置通知 advisor.setPointcut(myPointcut);//配置切入点 ProxyFactory proxyFactory=new ProxyFactory(); //ProxyFactory proxyFactory=new ProxyFactory(target);//这样的话就它会自动将target对象所有实现的接口都代理 proxyFactory.addAdvisor(advisor); proxyFactory.addAdvice(null/*自定义的拦截器*/);//添加更多的通知,内部会将它封装成Advisor. proxyFactory.setTarget(target); proxyFactory.setInterfaces(target.getClass().getInterfaces());//指定要代理的接口,如果使用new ProxyFactory(target);创建ProxyFactory的话这句可以省略 Target targetProxy=(Target)proxyFactory.getProxy();//创建并获取代理对象 targetProxy.method();
2、ProxyFactoryBean继承自ProxyCreatorSupport实现了FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware接口
<bean class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interceptorNames">interceptor*</property> <property name="target" ref="targetObject" /> </bean>
3、TransactionProxyFactoryBean事务代理工厂Bean它依赖于ProxyFactoryBean创建代理,并添加了处理事务开关的TransactionInterceptor拦截器.
<bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="target" ref="targetObject"></property> <property name="transactionManager" ref="transactionManager"></property> <property name="transactionAttributes"> <props> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
4、BeanNameAutoProxyCreator
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <value>user*,authenticateService</value> </property> <property name="interceptorNames"> <value>loggerInterceptor,interceptor*</value> </property> </bean>
相关推荐
AOP核心组件包括几个关键概念,如切面(Aspect)、通知(Advice)、连接点(Joinpoint)和织入(Weaving)。而AnnotationAwareAspectJAutoProxyCreator是AOP中一个非常核心的类,它是作为后置处理器...
《Spring AOP 源码分析》 在深入探讨Spring AOP之前,我们先要理解AOP(面向切面编程)的基本概念。AOP是一种编程范式,它将关注点分离,使得我们可以将横切关注点(如日志、事务管理、安全检查等)与业务逻辑解耦...
**三、项目源码分析** 项目的源码包含了一个简单的Spring AOP示例,可能包括以下几个部分: 1. `Aspect`类:包含了切面逻辑的类,通常有多个通知方法。 2. `Service`类:业务逻辑类,切面将会影响到的方法。 3. `...
接下来,我们将深入到Spring AOP的核心源码来理解其如何工作。关键在于理解代理对象是如何处理方法调用的。这里涉及到了Spring AOP中的动态代理机制。当调用代理对象的方法时,实际上会进入一个回调函数,如下所示:...
导入Spring AOP源码到Eclipse工程后,可以通过调试和阅读源码,了解通知的创建、切点的匹配、代理的生成等核心流程,进一步理解Spring AOP的工作原理。 总结,Spring AOP源码的探索有助于开发者深入理解面向切面...
通过源码分析,我们可以深入了解Spring AOP的工作原理,以及如何通过`IntroductionInterceptor`或`@AspectJ`来实现引入。理解并熟练运用这一特性,将有助于我们在实际开发中更好地进行代码解耦和模块化,提升软件的...
在深入理解 Spring AOP 的源码时,需要熟悉 Spring IoC 的工作原理,以及 AOP 相关的概念,如切点表达式、通知类型等。了解这些基础知识可以帮助我们更好地掌握 Spring AOP 的实现细节。在分析源码时,可以参考作者...
标题和描述中提到的是关于Spring AOP源码的电子书。Spring AOP(Aspect-Oriented Programming)是Spring框架的一个重要组成部分,它支持面向切面编程的实践,是为了解决面向对象编程中的横切关注点问题而设计的。在...
**Spring AOP介绍** ...学习并掌握Spring AOP及其源码分析对于提升作为IT专业人员的技术水平至关重要,它不仅能够帮助我们编写更加优雅和简洁的代码,还能使我们更好地应对复杂的企业级应用需求。
在本文中,我们将从实现的角度来认识 SpringAOP 框架,从外部接口、内部实现、组成部分、执行过程四个方面来介绍 Spring AOP 框架的结构分析。 最后,本文的目标是从实现的角度来认识 SpringAOP 框架,观察的角度是...
在本文中,我们将深入探讨Spring AOP的运用,并结合源码分析其工作原理。 首先,了解AOP的基本概念: 1. 切面(Aspect):切面是关注点的模块化,这些关注点通常是跨越多个对象的横切关注点,例如事务管理、日志...
本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际应用。 1. **核心概念** - **切面(Aspect)**:切面是关注点的模块化,包含业务逻辑之外的横切关注点,如日志、事务管理。 - **连接点(Join Point...
5. **源码分析**: 在`ProxyFactoryBean`的`getObject()`方法中,会调用`createAopProxy()`生成`AopProxy`,然后`AopProxy`的`getProxy()`方法返回实际的代理对象。`createAopProxy()`会根据配置判断使用JDK还是...
Spring AOP的源码分析** - **AOP代理创建**: Spring如何创建JDK或CGLIB代理对象。 - **通知执行流程**: 当一个方法被调用时,Spring如何识别切入点并执行相应的通知。 - **切入点表达式解析**: 如何解析和匹配切入...
本文将围绕Spring AOP的源码分析,探讨其核心概念、工作原理以及在实际开发中的应用。 一、AOP核心概念 1. 切面(Aspect):切面是关注点的模块化,通常包含一组通知(advises)和一个切入点(pointcut)定义。 2...
本篇文章将深入探讨如何使用Spring AOP实现性能监控器,并通过源码分析来理解其工作原理。 首先,我们要了解AOP的核心概念——切面(Aspect)、通知(Advice)、连接点(Join Point)、切入点(Pointcut)和织入...
9. **源码分析** 深入研究Spring AOP的源码,可以帮助我们更好地理解其工作原理,例如,可以查看`org.springframework.aop.framework.ProxyFactoryBean`、`org.springframework.aop.aspectj.autoproxy....
这个压缩包文件包含了关于Spring AOP的实践源码,通过分析这些源码,我们可以深入理解Spring AOP的工作原理和实际应用。 在Spring AOP中,"切面"(Aspect)是核心概念,它封装了横切关注点,如日志、事务管理等。切...
Spring 源代码分析系列涵盖了多个关键模块,包括事务处理、IoC容器、JDBC、MVC、AOP以及与Hibernate和Acegi安全框架的集成。以下是对这些知识点的详细阐述: 1. **Spring 事务处理**:Spring 提供了声明式事务管理...
在本"Spring-AOP源码Demo"中,我们将深入探讨Spring AOP的工作原理以及如何通过源码学习其核心概念。 1. **AOP的基本概念** - **切面(Aspect)**:AOP的核心单元,它封装了横切关注点,包括通知(advice)、切入...