目录

  • 1. 准备
    • 1.1. 接口
    • 1.2. 接口的实现
    • 1.3. 切面类
    • 1.4. 测试类
    • 1.5. 测试结果
  • 2. `Spring Aop` 代理对象的产生
    • 2.1. 源码解读之前
    • 2.2. 抽象类 `AbstractBeanFactory` 的 `doGetBean()`
      • 2.2.1. 单例 `bean` 的创建
      • 2.2.2. 单例 `bean` 的创建 `createBean()`
        • 2.2.2.1 单例 `bean` 具体创建的 `doCreateBean()`
          • 2.2.2.1.1 单例 `bean` 初始化的 `initializeBean()`
          • 2.2.2.1.2. 进入 `initializeBean()`
          • 2.2.2.1.3. `initializeBean()` 流程步骤
  • 3. 代理对象产生流程步骤

1. 准备

1.1. 接口

public interface UserService {String query();
}

1.2. 接口的实现

@Service
public class UserServiceImpl implements UserService {@Overridepublic String query() {System.out.println("------------ yz ------------");return "yz";}
}

1.3. 切面类

@Aspect
@Component
public class AopConfig {@Pointcut(value = "execution(* com.atguigu.springIOC.UserServiceImpl.*(..))")public void businessService() {}@Before(value = "businessService()")public void doBefore() {System.out.println("----------------- doBefore -----------------");}@AfterReturning(value = "businessService()")public void doAfterReturning() {System.out.println("----------------- doAfterReturning -----------------");}@After(value = "businessService()")public void doAfter() {System.out.println("----------------- doAfter -----------------");}
}

1.4. 测试类

// 该注解在测试时必须添加;在使用 springboot 较高版本启动运行程序时,可以不添加
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"com.atguigu.springIOC"})
public class BeanTest {public static void main(String[] args) {// 获取 spring IOC 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);// 从容器中获取 beanUserService userService = (UserService) applicationContext.getBean("userServiceImpl");String query = userService.query();System.out.println(query);}
}

1.5. 测试结果

----------------- doBefore -----------------
------------ yz ------------
----------------- doAfter -----------------
----------------- doAfterReturning -----------------
yz

2. Spring Aop 代理对象的产生

2.1. 源码解读之前

既然要产生代理对象,我们进行源码分析,无非就是从下面两行代码入手

// 获取 spring IOC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);
// 从容器中获取 bean
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");

通过 spring 初始化 bean(单例) 过程 的文章分析,userServiceImpl 这个 bean 会通过 getBean() 从一级缓存 singletonObjects 中能获取到。那么 userServiceImpl 的代理对象肯定从下面的代码中产生

// 获取 spring IOC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);

2.2. 抽象类 AbstractBeanFactorydoGetBean()

关于代码

// 获取 spring IOC 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanTest.class);

的过程,鉴于篇幅本篇文章不再详细赘述,详细过程请查看,我们从这个 doGetBean 方法开始

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两个原因// 1、name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean//   实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储//   方式是一致的,即 <beanName, bean>,beanName 中是没有 & 这个字符的。所以我们需要//   将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。// 2、还是别名的问题,转换需要 &beanNamefinal String beanName = transformedBeanName(name);Object bean;// 先从缓存中获取,因为在容器初始化的时候或者其他地方调用过getBean,已经完成了初始化Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.debug("Returning cached instance of singleton bean '" + beanName + "'");}}// 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果// sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的// bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回// 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// 如果是原型不应该在初始化的时候创建,在这里直接抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 获取parentBeanFactoryBeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {String nameToLookup = originalBeanName(name);// 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {return (T) parentBeanFactory.getBean(nameToLookup, args);}else {return parentBeanFactory.getBean(nameToLookup, requiredType);}}if (!typeCheckOnly) {// 添加到alreadyCreated set集合当中,表示他已经创建过一次,做标记markBeanAsCreated(beanName);}try {// 根据beanName重新获取MergedBeanDefinition(步骤6将MergedBeanDefinition删除了,这边获取一个新的)final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// 检查MergedBeanDefinitioncheckMergedBeanDefinition(mbd, beanName, args);// 拿到当前bean依赖的bean名称集合,在实例化自己之前,需要先实例化自己依赖的beanString[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {// 遍历当前bean依赖的bean名称集合for (String dep : dependsOn) {// 检查dep是否依赖于beanName,即检查是否存在循环依赖if (isDependent(beanName, dep)) {// 如果是循环依赖则抛异常throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 将dep和beanName的依赖关系注册到缓存中registerDependentBean(dep, beanName);try {// 获取dep对应的bean实例,如果dep还没有创建bean实例,则创建dep的bean实例getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// scope为 singleton 的bean创建if (mbd.isSingleton()) {             sharedInstance = getSingleton(beanName, () -> {try {// 创建Bean实例return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});// 返回beanName对应的实例对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}// scope为 prototype 的bean创建    else if (mbd.isPrototype()) {                   Object prototypeInstance = null;try {// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)beforePrototypeCreation(beanName);// 创建Bean实例prototypeInstance = createBean(beanName, mbd, args);}finally {// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)afterPrototypeCreation(beanName);}// 返回beanName对应的实例对象bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {// 既不是单例也不是原型的 bean创建,可能是 request之类的// 根据scopeName,从缓存拿到scope实例String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {// 既不是单例也不是原型的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)Object scopedInstance = scope.get(beanName, () -> {// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)afterPrototypeCreation(beanName);}});// 返回beanName对应的实例对象bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +"defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}catch (BeansException ex) {// 如果创建bean实例过程中出现异常,则将beanName从alreadyCreated缓存中移除cleanupAfterBeanCreationFailure(beanName);throw ex;}}// 检查所需类型是否与实际的bean对象的类型匹配if (requiredType != null && !requiredType.isInstance(bean)) {try {// 类型不对,则尝试转换bean类型T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;
}

注意下面的代码,第一次(启动初始化 IOC 容器时 )sharedInstance 肯定为 null

// 先从缓存中获取,因为在容器初始化的时候或者其他地方调用过getBean,已经完成了初始化
Object sharedInstance = getSingleton(beanName);

2.2.1. 单例 bean 的创建

由于 userServiceImpl 是单例的,所以我们重点关注

if (mbd.isSingleton()) {// scope为 singleton 的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)sharedInstance = getSingleton(beanName, () -> {try {// 创建Bean实例return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});// 返回beanName对应的实例对象// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

在这里使用 idea 条件断点进行代码调试,在下面这行打断点

sharedInstance = getSingleton(beanName, () -> {


进入 getSingleton 方法如下图


重新打条件断点,进入 singletonFactory.getObject() 方法

2.2.2. 单例 bean 的创建 createBean()

来到 AbstractAutowireCapableBeanFactorycreateBean 方法

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {if (logger.isDebugEnabled()) {logger.debug("Creating instance of bean '" + beanName + "'");}// 确保对应BeanClass完成解析,具体表现是进行了ClassLoder.loadClass或Class.forName完成了类加载resolveBeanClass(mbd, beanName);try {// 准备方法覆盖,主要为lookup-method,replace-method等配置准备mbd.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbd.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// 供特定后置处理器拓展,如果直接生成了一个Bean,就直接返回不走正常创建流程。// 具体逻辑是判断当前Spring容器是否注册了实现了InstantiationAwareBeanPostProcessor接口的后置处理器// 如果有,则依次调用其中的applyBeanPostProcessorsBeforeInstantiation方法,如果中间任意一个方法返回不为null,直接结束调用。// 然后依次所有注册的BeanPostProcessor的postProcessAfterInitialization方法(同样如果任意一次返回不为null,即终止调用。Object bean = resolveBeforeInstantiation(beanName, mbd);// 如果不为空,说明提前生成了实例,直接返回if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}// 具体创建Bean逻辑Object beanInstance = doCreateBean(beanName, mbd, args);if (logger.isDebugEnabled()) {logger.debug("Finished creating instance of bean '" + beanName + "'");}return beanInstance;
}

断点调试发现,下面会产生代理对象,继续追踪

// 具体创建Bean逻辑
Object beanInstance = doCreateBean(beanName, mbd, args);

2.2.2.1 单例 bean 具体创建的 doCreateBean()

来到了 AbstractAutowireCapableBeanFactorydoCreateBean 方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// BeanWrapper封装了具体的Bean实例,然后可以很方便地通过调用getPropertyValue和setPropertyValue等方法反射读写Bean的具体属性BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {// 先尝试从缓存中取instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {// 调用构造方法创建一个空实例对象,并用BeanWrapper进行包装instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// 获取所有的后置处理器,如果后置处理器实现了MergedBeanDefinitionPostProcessor接口,则一次调用其postProcessMergedBeanDefinition方法synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// 如果满足循环依赖缓存条件,先缓存具体对象boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}         // 循环依赖处理逻辑:将已完成实例化,但是未完成属性赋值和相关的初始化的一个不完整的 bean 添加到三级缓存 singletonFactories 中// 具体内部会遍历后置处理器,判断是否有SmartInstantiationAwareBeanPostProcessor的实现类,然后调用里面getEarlyBeanReference覆盖当前Bean// 默认不做任何操作返回当前Bean,作为拓展,这里比如可以供AOP来创建代理类addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 开始对Bean实例进行初始化Object exposedObject = bean;try {// 对bean进行属性填充,在这里面完成依赖注入的相关内容populateBean(beanName, mbd, instanceWrapper);// 完成属性依赖注入后,进一步初始化Bean// 具体进行了以下操作:// 1.若实现了BeanNameAware, BeanClassLoaderAware,BeanFactoryAwareAware等接口,则注入相关对象// 2.遍历后置处理器,调用实现的postProcessBeforeInitialization方法,// 3.如果实现了initialzingBean,调用实现的 afterPropertiesSet()// 4.如果配置了init-mothod,调用相应的init方法// 5.遍历后置处理器,调用实现的postProcessAfterInitializationexposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// 如果实现了Disposable接口,会在这里进行注册,最后在销毁的时候调用相应的destroy方法try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;
}
2.2.2.1.1 单例 bean 初始化的 initializeBean()

doCreateBean() 中会产生代理对象的代码(注意:代理对象的产生是在实例化 beanbean 的属性填充之后进行的)

exposedObject = initializeBean(beanName, exposedObject, mbd);

doCreateBean(beanName, mbd, args) 的主要方法流程

  • createBeanInstance(beanName, mbd, args):实例化 bean,调用对象的构造方法实例化对象
  • addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName,mbd, bean)):将已完成实例化,但是未完成属性赋值和相关的初始化的一个不完整的 bean 添加到三级缓存 singletonFactories
  • populateBean(beanName, mbd, instanceWrapper):对 bean 进行属性填充
  • initializeBean(beanName, exposedObject, mbd):完成 bean 的属性填充注入后,进一步初始化 bean,在此过程中产生代理对象。此时 bean 的创建工作正式完成,已经可以在项目中使用了
  • registerDisposableBeanIfNecessary(beanName, bean, mbd):如果符合 bean 的销毁条件,则执行单例bean 的销毁工作
2.2.2.1.2. 进入 initializeBean()

进入 AbstractAutowireCapableBeanFactoryinitializeBean 方法

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 第一步:先执行所有的AwareMethodsif (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());} else {// 如果实现了Aware接口,就对该bean进行一些设置// 比如实现了BeanNameAware接口,那么对其bean的属性beanName上设置对应的beanName// 如果实现了BeanFactoryAware接口,那么对其beanFactory属性设置上创建该bean使用的bean工厂invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 执行所有的BeanPostProcessor#postProcessBeforeInitialization  初始化之前的处理器方法// 规则:只要谁反悔了null,后面的就都不要执行了// 这里面实现postProcessBeforeInitialization 的处理器就很多了,有很多对Aware进行了扩展的wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 如果bean实现了InitializingBean或者用户自定义的init方法方法,那么调用这些初始化方法对bean的属性进行一些个性化设置invokeInitMethods(beanName, wrappedBean, mbd);} catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// 执行后置处理器的postProcessAfterInitialization方法。AOP的原理和实现就在其中wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}
2.2.2.1.3. initializeBean() 流程步骤
  1. 调用各类感知 Aware 接口
  2. 执行 applyBeanPostProcessorsBeforeInitialization 初始化前的处置操作
  3. 调用 InitializingBean 接口初始化 (如果配置了method-init,则调用其方法初始化 )
  4. 调用 applyBeanPostProcessorsAfterInitialization 初始化之后的处置操作,AOP 的原理和实现就在其中

3. 代理对象产生流程步骤

  1. IOC 容器启动初始化时,首先会去一级缓存 singletonObjects 中去获取(肯定没有)
  2. 在根据当前 bean 的具体作用域,去初始化 bean
  3. 在做完 bean 的一些校验之后,会进行 bean 的实例化,即调用 createBeanInstance() 方法
  4. 如果存在 bean 的循环依赖的情况,会将当前已实例化的 bean put 进三级缓存 singletonFactories
  5. 接着会进行 bean 的相关属性填充,即调用 populateBean() 方法,注意此时还并没有产生代理对象
  6. 再接着会进行 bean 的初始化操作,即调用 initializeBean() 方法
  7. 后续更新查看

Spring之Aop代理对象的产生(一)相关推荐

  1. Spring之AOP代理模式

    代理模式分类: 静态代理 动态代理 你要租房,不找房东,找中介,中介是房东的代理. 1.1静态代理 角色分析 抽象角色:一般会使用接口或者抽象类来解决 /*** @author LongXi* @cr ...

  2. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  3. Spring AOP源码(2)—AspectJAwareAdvisorAutoProxyCreator创建代理对象【两万字】

      基于最新Spring 5.x,介绍了Spring AOP中的AspectJAwareAdvisorAutoProxyCreator自动代理创建者的工作流程,对于创建代理对象的源码进行了深度分析! ...

  4. spring事务--使用aop事务代理对象调用方法示例

    第一种获取aop代理对象的方式: 第二种方式获取aop代理对象:

  5. 动态代理以及对应Spring中AOP源码分析

    AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理. 我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理.以下是两种动态代理 ...

  6. spring的aop的动态代理机制都有哪些_Spring学习(4):Spring AOP

    Spring AOP说明 AOP(Aspect Oriented Pragraming)面向切面编程,AOP采用横向抽取机制,取代了传统纵向继承体系的重复性代码(性能监视.事务管理.安全检查.缓存). ...

  7. Spring通知类型及使用ProxyFactoryBean创建AOP代理

    Spring 通知类型 通知(Advice)其实就是对目标切入点进行增强的内容,Spring AOP 为通知(Advice)提供了 org.aopalliance.aop.Advice 接口. Spr ...

  8. 手写Spring-第十五章-我也要注入?为代理对象注入属性,完善AOP

    前言 我们上一章实现了用注解为对象注入属性.但是还有一个地方我们没有照顾到,那就是代理对象属性的注入.你可能会疑惑,我们的Bean,不都是通过cglib代理出来的吗?那不都是代理对象?但我们这里说的代 ...

  9. AOP之proceedingjoinpoint和joinpoint区别(获取各对象备忘)、动态代理机制及获取原理代理对象、获取Mybatis Mapper接口原始对象...

    现在AOP的场景越来越多,所以我们有必要理解下和AOP相关的一些概念和机制. import org.aspectj.lang.reflect.SourceLocation; public interf ...

  10. Spring学习总结——Spring实现AOP的多种方式

    目录 一.基于XML配置的Spring AOP 二.使用注解配置AOP 三.AspectJ切点函数 四.AspectJ通知注解 五.零配置实现Spring IoC与AOP 六.示例下载 AOP(Asp ...

最新文章

  1. JAVA拾遗--关于SPI机制
  2. 生成Base58格式的UUID(Hibernate Base64格式的UUID续)
  3. java修饰符继承_Java修饰符和继承
  4. JAVA_出神入化学习路线大纲
  5. 《用python写网络爬虫》完整版+源码
  6. 智能客户端(Smart Client )中文文档及案例(转贴)
  7. 解决vbox挂载VBoxGuestAdditions失败
  8. windos不能在本地计算机启动服务器,WDS 服务器可能无法启动 - Windows Server | Microsoft Docs...
  9. Livereload介绍
  10. Automative SPICE 之五 过程能力层次和过程属性
  11. 计算单词的长度C++
  12. Javascript带按钮的轮播广告
  13. c++多线程之packaged_task
  14. Apple Watch更懂女人心
  15. 5.PS-快速选择和魔棒
  16. 分发服务器性能,高性能P2P流媒体内容分发服务器的设计与实现
  17. qlv视频转换器免费版_腾讯视频素材下载和转换教程
  18. Java实现hanoi塔
  19. 7-6 7-7 7-8 7-9 7-10
  20. windows 修改磁盘盘符教程

热门文章

  1. 阿里灵杰问天引擎电商搜索 -- 数据说明
  2. CTR介绍,数据集往往为表格形式,训练集使用历史的日志数据,然后进行特征归一化、离散化和特征哈希等操作,最终一条训练集为一行多列的二分类任务。
  3. android camera调试打印信息,Android : 高通平台Camera调试
  4. flutter能开发游戏吗_Flutter开发游戏初体验,喜大普奔
  5. 顺序容器和关联容器添加新元素方法详解
  6. java打开文件对话框
  7. 基于python快速实现排列组合算法
  8. 基础集合论笔记 目录
  9. 锁php_php+redis实现分布式锁
  10. android获取当前显示的view,Android中ViewPager获取当前显示的Fragment