Spring中AOP相关的API及源码解析,原来AOP是这样子的(3)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring中AOP相关的API及源码解析,原来AOP是这样子的(3)

Auto-proxy(实现自动AOP代理)


自动代理机制的实现其实很简单,就是通过Bean的后置处理器,在创建Bean的最后一步对Bean进行代理,并将代理对象放入到容器中。

实现自动代理的核心类就是AbstractAutoProxyCreator。我们来看看它的继承关系

image.png

为了更好的体会自动代理的作用,我们对它的三个具体的实现类来进行分析,分别是


  1. BeanNameAutoProxyCreator
  2. DefaultAdvisorAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator


BeanNameAutoProxyCreator


使用示例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean class="com.dmz.spring.initalize.service.DmzService" name="dmzService"/>
  <bean id="aroundAdvice" class="com.dmz.spring.initalize.aop.advice.DmzAroundAdvice"/>
  <bean id="beforeAdvice" class="com.dmz.spring.initalize.aop.advice.DmzBeforeAdvice"/>
    <!--使用很简单,只要配置一个BeanNameAutoProxyCreator即可-->
  <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" name="autoProxyCreator">
        <!--使用cglib代理-->
    <property name="proxyTargetClass" value="true"/>
         <!--对所有以dmz开头的bean进行自动代理-->
    <property name="beanNames" value="dmz*"/>
        <!--添加两个通知-->
    <property name="interceptorNames">
      <list>
        <value>beforeAdvice</value>
        <value>aroundAdvice</value>
      </list>
    </property>
  </bean>
</beans>
public class SourceMain {
  public static void main(String[] args) {
    ClassPathXmlApplicationContext cc =
        new ClassPathXmlApplicationContext("application-init.xml");
    DmzService dmzProxy = ((DmzService) cc.getBean("dmzService"));
    dmzProxy.testAop();
  }
}
// 程序打印:
// before invoke method [testAop],aop before logic invoked
// aroundAdvice invoked
// testAop invoke

DefaultAdvisorAutoProxyCreator


使用示例

在上面例子的基础上我们要修改配置文件,如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean class="com.dmz.spring.initalize.service.DmzService" name="dmzService"/>
  <bean id="aroundAdvice" class="com.dmz.spring.initalize.aop.advice.DmzAroundAdvice"/>
  <bean id="beforeAdvice" class="com.dmz.spring.initalize.aop.advice.DmzBeforeAdvice"/>
  <bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="dmzBeforeAdvisor">
    <property name="advice" ref="beforeAdvice"/>
  </bean>
  <bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="dmzAroundAdvisor">
    <property name="advice" ref="aroundAdvice"/>
  </bean>
  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
      id="advisorAutoProxyCreator">
        <!--这两个参数标明了我们要使用所有以dmz开头的Advisor类型的通知
        这里必须配置是Advisor,不能是Advice或者interceptor,
      可以看到DefaultAdvisorAutoProxyCreator跟BeanNameAutoProxyCreator的区别在于
      BeanNameAutoProxyCreator需要指定要被代理的bean的名称,
      而DefaultAdvisorAutoProxyCreator不需要,它会根据我们传入的Advisor
        获取到需要被代理的切点
    -->
    <property name="usePrefix" value="true"/>
    <property name="advisorBeanNamePrefix" value="dmz"/>
        <property name="proxyTargetClass" value="true"/>
  </bean>
</beans>

测试代码就不放了,大家可以自行测试,肯定是没问题的


AnnotationAwareAspectJAutoProxyCreator


我们正常在使用AOP的时候都会在配置类上添加一个@EnableAspectJAutoProxy注解,这个注解干了什么事呢?

实际就是向容器中注册了一个AnnotationAwareAspectJAutoProxyCreator。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 这里导入了一个类
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
  boolean proxyTargetClass() default false;
  boolean exposeProxy() default false;
}

通过@EnableAspectJAutoProxy导入了一个AspectJAutoProxyRegistrar,这个类会向容器中注册一个AnnotationAwareAspectJAutoProxyCreator,对应源码如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
  @Override
  public void registerBeanDefinitions(
      AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 在这里完成的注册
    // 最终会调用到AopUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法
        // 完成AnnotationAwareAspectJAutoProxyCreator这个bd的注册
    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        // 解析注解的属性
        // proxyTargetClass:为true的话开启cglib代理,默认为jdk代理
        // exposeProxy:是否将代理对象暴露到线程上下文中
    AnnotationAttributes enableAspectJAutoProxy =
        AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    if (enableAspectJAutoProxy != null) {
      if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      }
      if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
        AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
      }
    }
  }
}

前面已经说过了,自动代理机制实际上就是Spring在内部new了一个ProxyFactory,通过它创建了一个代理对象。对应的代码就在AbstractAutoProxyCreator中的createProxy方法内,源码如下:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                             @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
  // 看到了吧,这里创建了一个proxyFactory
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
  // 通过proxyFactory来创建一个代理对象
    return proxyFactory.getProxy(getProxyClassLoader());
}

关于这个类的执行流程在下篇文章中我再详细介绍,接下来我们要分析的就是具体创建AOP代理的源码了。对应的核心源码就是我们之前所提到的

createAopProxy().getProxy();

这行代码分为两步,我们逐步分析


1.调用AopProxyFactory的createAopProxy()方法获取一个AopProxy对象

2.调用AopProxy对象的getProxy()方法


核心源码分析


createAopProxy方法分析


AopProxyFactory在Spring中只有一个默认的实现类,就是DefaultAopProxyFactory,它的对应的createAopProxy的是实现代码如下:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    // 就是通过AOP相关的配置信息来决定到底是使用cglib代理还是jdk代理
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 如果开启了优化,或者ProxyTargetClass设置为true
        // 或者没有提供代理类需要实现的接口,那么使用cglib代理
        // 在前面分析参数的时候已经说过了
        // 默认情况下Optimize都为false,也不建议设置为true,因为会进行一些侵入性的优化
        // 除非你对cglib的优化非常了解,否则不建议开启
        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.");
            }
            // 需要注意的是,如果需要代理的类本身就是一个接口
            // 或者需要被代理的类本身就是一个通过jdk动态代理生成的类
            // 那么不管如何设置都会使用jdk动态代理
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        // 否则都是jdk代理
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
  // 判断是否提供代理类需要实现的接口
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }
}

getProxy方法分析


从对createAopProxy方法的分析可以看到,我们要么执行的是ObjenesisCglibAopProxy中的getProxy方法,要么就是JdkDynamicAopProxy的getProxy方法,二者的区别在于一个是通过cglib的方式生成代理对象,而后者则是通过jdk的方式生成动态代理。


这里我只分析一个JdkDynamicAopProxy,首先我们来看看这个类的继承关系


希望你之前已经阅读过

原创 动态代理学习(一)自己动手模拟JDK动态代理

原创 动态代理学习(二)JDK动态代理源码分析

image.png

可以看到这个类本身就是一个InvocationHandler,这意味着当调用代理对象中的方法时,最终会调用到JdkDynamicAopProxy的invoke方法。

所以对于这个类我们起码应该关注两个方法

1.getProxy方法

2.invoke方法

getProxy方法源码如下:

public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    }
    // 这里获取到代理类需要实现的所有的接口
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    // 需要明确是否在接口定义了hashCode以及equals方法
    // 如果接口中没有定义,那么在调用代理对象的equals方法的时候
    // 如果两个对象相等,那么意味着它们的目标对象,通知以及实现的接口都相同
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

我们再来看看到底是怎么获取到需要实现的接口的

static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
    // 第一步:获取在配置中指定的需要实现的接口
    Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
    // 第二步:如果没有指定需要实现的接口,但是需要代理的目标类本身就是一个接口
    // 那么将其添加到代理类需要实现的接口的集合中
    // 如果目标类本身不是一个接口,但是是经过jdk代理后的一个类
    // 那么获取这个代理后的类所有实现的接口,并添加到需要实现的接口集合中
    if (specifiedInterfaces.length == 0) {
        Class<?> targetClass = advised.getTargetClass();
        if (targetClass != null) {
            if (targetClass.isInterface()) {
                advised.setInterfaces(targetClass);
            }
            else if (Proxy.isProxyClass(targetClass)) {
                advised.setInterfaces(targetClass.getInterfaces());
            }
            specifiedInterfaces = advised.getProxiedInterfaces();
        }
    }
    // 第三步:为代理类添加三个默认需要实现的接口,分别是
    // 1.SpringProxy,一个标记接口,代表这个类是通过Spring的AOP代理生成的
    // 2.Advised,提供了管理通知的方法
    // 3.DecoratingProxy,用户获取到真实的目标对象
    // 这个真实对象指的是在嵌套代理的情况下会获取到最终的目标对象
    // 而不是指返回这个ProxyFactory的target
    boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
    boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
    boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
    int nonUserIfcCount = 0;
    if (addSpringProxy) {
        nonUserIfcCount++;
    }
    if (addAdvised) {
        nonUserIfcCount++;
    }
    if (addDecoratingProxy) {
        nonUserIfcCount++;
    }
    Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
    System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
    int index = specifiedInterfaces.length;
    if (addSpringProxy) {
        proxiedInterfaces[index] = SpringProxy.class;
        index++;
    }
    if (addAdvised) {
        proxiedInterfaces[index] = Advised.class;
        index++;
    }
    if (addDecoratingProxy) {
        proxiedInterfaces[index] = DecoratingProxy.class;
    }
    return proxiedInterfaces;
}

invoke方法分析


在确认了需要实现的接口后,直接调用了jdk的动态代理方法,这个我们就不做分析了,接下来我们来看看Spring是如何将通知应用到代理对象上的,对应的要分析的代码就是JdkDynamicAopProxy的invoke方法,源码如下:

// 这个方法的代码稍微有点长,代码也比较难,希望大家能耐心看完
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;
    try {
        // 首先处理的是hashCode跟equals方法
        // 如果接口中没有定义这两个方法,那么会调用本类中定义的equals方法
        // 前面我们也说过了,只有当两个类的目标对象,通知以及实现的接口都相等的情况下
        // equals才会返回true
        // 如果接口中定义了这两个方法,那么最终会调用目标对象中的方法
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            return equals(args[0]);
        }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            return hashCode();
        }
        // 也就是说我们调用的是DecoratingProxy这个接口中的方法
        // 这个接口中只定义了一个getDecoratedClass方法,用于获取到
        // 最终的目标对象,在方法实现中会通过一个while循环来不断接近
        // 最终的目标对象,直到得到的目标对象不是一个被代理的对象才会返回
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 说明调用的是Advised接口中的方法,这里只是单纯的进行反射调用
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                 method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }
        Object retVal;
        // 说明需要将代理类暴露到线程上下文中
        // 调用AopContext.setCurrentProxy方法将其放入到一个threadLocal中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 接下来就是真正的执行代理逻辑了
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 先获取整个拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        // 如果没有进行拦截,直接反射调用方法
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        // 否则开始执行整个链条
        else {
            MethodInvocation invocation =
                new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            retVal = invocation.proceed();
        }
        // 这里是处理一种特殊情况,就是当执行的方法返回值为this的情况
        // 这种情况下,需要返回当前的代理对象而不是目标对象
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

在上面整个流程中,我们抓住核心的两步

1.获取整个拦截器链

2.开始在拦截器链上执行方法

我们先看第一步,对应源码如下:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 调用了advisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, @Nullable Class<?> targetClass) {
    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    // 是否有引入通知
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    // 获取到所有的通知
    for (Advisor advisor : config.getAdvisors()) {
        // 除了引入通知外,可以认为所有的通知都是一个PointcutAdvisor
        if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            // config.isPreFiltered:代表的是配置已经过滤好了,是可以直接应用的
            // 这句代码的含义就是配置是预过滤的或者在类级别上是匹配的
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 接下来要判断在方法级别上是否匹配
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    // 将通知转换成对应的拦截器
                    // 有些通知本身就是拦截器,例如环绕通知
                    // 有些通知需要通过一个AdvisorAdapter来适配成对应的拦截器
                    // 例如前置通知,后置通知,异常通知等
                    // 其中MethodBeforeAdvice会被适配成MethodBeforeAdviceInterceptor
                    // AfterReturningAdvice会被适配成AfterReturningAdviceInterceptor
                    // ThrowAdvice会被适配成ThrowsAdviceInterceptor
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // 如果是动态的拦截,会创建一个InterceptorAndDynamicMethodMatcher
                    // 动态的拦截意味着需要根据具体的参数来决定是否进行拦截
                    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(actualClass)) {
                // 前文我们有提到过,引入通知实际就是通过一个拦截器
                // 将方法交由引入的类执行而不是目标类
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            // 可能会扩展出一些通知,一般不会
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }
    return interceptorList;
}

在构建好拦截器链后,接下来就是真正执行方法了,对应代码就是

// 先创建一个MethodInvocation
MethodInvocation invocation =
    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 开始在拦截器链上执行这个方法
retVal = invocation.proceed();

最后的关键代码就落在了ReflectiveMethodInvocation的proceed方法

public Object proceed() throws Throwable {
    // 满足这个条件,说明执行到了最后一个拦截器,那么直接反射调用目标方法
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }
    // 获取到下一个要执行的拦截器
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // 前面构建拦截器链的时候我们可以看到,动态的拦截的话会创建一个InterceptorAndDynamicMethodMatcher
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
        // 如果匹配失败了,执行拦截器链中的下一个拦截逻辑
         return proceed();
      }
   }
   else {
    // 调用拦截器中的invoke方法,可以看到这里将this作为参数传入了
      // 所以我们在拦截器中调用 MethodInvocation的proceed时又会进行入当前这个方法
      // 然后去执行链条中的下一个拦截器 
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

总结


本文主要是为下篇文章做准备,下篇文章将会结束整个IOC流程的分析,IOC的最后一步便是为Bean创建代理。本文已经分析了代理的具体创建逻辑,在下篇文章中我们主要结合Spring的启动流程来看一看Spring是如何将通知添加到创建代理的配置信息中去的。


关于整个IOC跟AOP的模块还会有两篇文章,一篇用于结束整个IOC流程,另外一篇专门探讨Spring中循环依赖的解决。完成这两篇文章中,接下来打算用5到7篇文章对Spring的事务管理进行分析!


相关文章
|
26天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
12天前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
12天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
54 8
|
1月前
|
存储 安全 Java
Spring Boot 编写 API 的 10条最佳实践
本文总结了 10 个编写 Spring Boot API 的最佳实践,包括 RESTful API 设计原则、注解使用、依赖注入、异常处理、数据传输对象(DTO)建模、安全措施、版本控制、文档生成、测试策略以及监控和日志记录。每个实践都配有详细的编码示例和解释,帮助开发者像专业人士一样构建高质量的 API。
|
1月前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
63 2
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
182 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
69 2
|
2月前
|
前端开发 Java 开发者
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
141 0
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
108 2
|
26天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

推荐镜像

更多