最后
这份文档从构建一个键值数据库的关键架构入手,不仅带你建立起全局观,还帮你迅速抓住核心主线。除此之外,还会具体讲解数据结构、线程模型、网络框架、持久化、主从同步和切片集群等,帮你搞懂底层原理。相信这对于所有层次的Redis使用者都是一份非常完美的教程了。
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
你的支持,我的动力;祝各位前程似锦,offer不断!!!
// 1.5 解析标记AspectJ注解中的增强方法
List classAdvisors = this.advisorFactory.getAdvisors(factory);
// 1.6 放到缓存中
if (this.beanFactory.isSingleton(beanName)) {
// 如果beanName是单例则直接将解析的增强方法放到缓存
this.advisorsCache.put(beanName, classAdvisors);
} else {
// 如果不是单例,则将factory放到缓存,之后可以通过factory来解析增强方法
this.aspectFactoryCache.put(beanName, factory);
}
// 1.7 将解析的增强器添加到advisors
advisors.addAll(classAdvisors);
} else {
// 如果per-clause的类型不是SINGLETON
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
// 名称为beanName的Bean是单例,但切面实例化模型不是单例,则抛异常
throw new IllegalArgumentException(“Bean with name '” + beanName +
“’ is a singleton, but aspect instantiation model is not singleton”);
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
// 将factory放到缓存,之后可以通过factory来解析增强方法
this.aspectFactoryCache.put(beanName, factory);
// 解析标记AspectJ注解中的增强方法,并添加到advisors中
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
// 1.9 将解析出来的切面beanName放到缓存aspectBeanNames
this.aspectBeanNames = aspectNames;
// 1.10 最后返回解析出来的增强器
return advisors;
}
}
}
// 2.如果aspectNames不为null,则代表已经解析过了,则无需再次解析
// 2.1 如果aspectNames是空列表,则返回一个空列表。空列表也是解析过的,只要不是null都是解析过的。
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 2.2 aspectNames不是空列表,则遍历处理
List advisors = new LinkedList();
for (String aspectName : aspectNames) {
// 根据aspectName从缓存中获取增强器
List cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
// 根据上面的解析,可以知道advisorsCache存的是已经解析好的增强器,直接添加到结果即可
advisors.addAll(cachedAdvisors);
} else {
// 如果不存在于advisorsCache缓存,则代表存在于aspectFactoryCache中,
// 从aspectFactoryCache中拿到缓存的factory,然后解析出增强器,添加到结果中
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
// 返回增强器
return advisors;
}
1.5 解析标记 AspectJ 注解中的增强方法,见代码块7。
代码块7:getAdvisors
@Override
public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 1.前面我们将beanClass和beanName封装成了aspectInstanceFactory的AspectMetadata属性,
// 这边可以通过AspectMetadata属性重新获取到当前处理的切面类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 2.获取当前处理的切面类的名字
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 3.校验切面类
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
// 4.使用装饰器包装MetadataAwareAspectInstanceFactory,以便它只实例化一次。
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List advisors = new LinkedList();
// 5.获取切面类中的方法(也就是我们用来进行逻辑增强的方法,被@Around、@After等注解修饰的方法,使用@Pointcut的方法不处理)
for (Method method : getAdvisorMethods(aspectClass)) {
// 6.处理method,获取增强器
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
// 7.如果增强器不为空,则添加到advisors
advisors.add(advisor);
}
}
// If it’s a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 8.如果寻找的增强器不为空而且又配置了增强延迟初始化,那么需要在首位加入同步实例化增强器(用以保证增强使用之前的实例化)
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 9.获取DeclareParents注解
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
6.处理 method,获取增强器,见代码块8。
代码块8:getAdvisor
@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 1.校验切面类
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 2.AspectJ切点信息的获取(例如:表达式),就是指定注解的表达式信息的获取,如:@Around(“execution(* com.joonwhee.open.aop..(…))”)
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 3.如果expressionPointcut为null,则直接返回null
if (expressionPointcut == null) {
return null;
}
// 4.根据切点信息生成增强器
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
2.AspectJ 切点信息的获取,见代码块9。
4.根据切点信息生成增强器,见代码块11。
代码块9:getPointcut
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 1.查找并返回给定方法的第一个AspectJ注解(@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut)
// 因为我们之前把@Pointcut注解的方法跳过了,所以这边必然不会获取到@Pointcut注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 2.如果方法没有使用AspectJ的注解,则返回null
if (aspectJAnnotation == null) {
return null;
}
// 3.使用AspectJExpressionPointcut实例封装获取的信息
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 提取得到的注解中的表达式,
// 例如:@Around(“execution(* com.joonwhee.open.aop..(…))”),得到:execution(* com.joonwhee.open.aop..(…))
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
ajexp.setBeanFactory(this.beanFactory);
return ajexp;
}
1.获取方法上的AspectJ注解,见代码块10。
代码块10:findAspectJAnnotationOnMethod
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
// 设置要查找的注解类
Class<?>[] classesToLookFor = new Class<?>[]{
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
for (Class<?> c : classesToLookFor) {
// 查找方法上是否存在当前遍历的注解,如果有则返回
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class) c);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
代码块11:new InstantiationModelAwarePointcutAdvisorImpl
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 1.简单的将信息封装在类的实例中
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
// aspectJAdviceMethod保存的是我们用来进行逻辑增强的方法(@Around、@After等修饰的方法)
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
// 2.是否需要延迟实例化
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it’s not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
} else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 3.实例化增强器:根据注解中的信息初始化对应的增强器
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
3.实例化增强器:根据注解中的信息初始化对应的增强器,见代码块12。
代码块12:instantiateAdvice
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
// ReflectiveAspectJAdvisorFactory.java
@Override
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 1.获取切面类
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 2.校验切面类(重复校验第3次…)
validate(candidateAspectClass);
// 3.查找并返回方法的第一个AspectJ注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it’s an AspectJ-annotated class
// 4.如果我们到这里,我们知道我们有一个AspectJ方法。检查切面类是否使用了AspectJ注解
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
“Offending method '” + candidateAdviceMethod + “’ in class [” +
candidateAspectClass.getName() + “]”);
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 5.根据方法使用的aspectJ注解创建对应的增强器,例如最常见的@Around注解会创建AspectJAroundAdvice
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug(“Processing pointcut '” + candidateAdviceMethod.getName() + “'”);
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice…
// 6.配置增强器
// 切面类的name,其实就是beanName
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
// 获取增强方法的参数
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 如果参数不为空,则赋值给springAdvice
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
// 最后,返回增强器
return springAdvice;
}
代码块13:findAdvisorsThatCanApply
public static List findAdvisorsThatCanApply(List candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List eligibleAdvisors = new LinkedList();
// 1.首先处理引介增强(@DeclareParents)用的比较少可以忽略,有兴趣的参考:https://www.cnblogs.com/HigginCui/p/6322283.html
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
// 2.遍历所有的candidateAdvisors
for (Advisor candidate : candidateAdvisors) {
// 2.1 引介增强已经处理,直接跳过
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 2.2 正常增强处理,判断当前bean是否可以应用于当前遍历的增强器(bean是否包含在增强器的execution指定的表达式中)
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
2.2 正常增强处理,判断当前 bean 是否可以应用于当前遍历的增强器,这边表达式判断的逻辑比较复杂,可以简单的理解为:判断 bean 是否包含在增强器的 execution 指定的表达式中。
代码块14:createProxy
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 1.初始化ProxyFactory
ProxyFactory proxyFactory = new ProxyFactory();
// 从当前对象复制属性值
proxyFactory.copyFrom(this);
// 检查proxyTargetClass属性,判断对于给定的bean使用类代理还是接口代理,
// proxyTargetClass值默认为false,可以通过proxy-target-class属性设置为true
if (!proxyFactory.isProxyTargetClass()) {
// 检查preserveTargetClass属性,判断beanClass是应该基于类代理还是基于接口代理
if (shouldProxyTargetClass(beanClass, beanName)) {
// 如果是基于类代理,则将proxyTargetClass赋值为true
proxyFactory.setProxyTargetClass(true);
} else {
// 评估bean的代理接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 将拦截器封装为Advisor(advice持有者)
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 将advisors添加到proxyFactory
proxyFactory.addAdvisors(advisors);
// 设置要代理的类,将targetSource赋值给proxyFactory的targetSource属性,之后可以通过该属性拿到被代理的bean的实例
proxyFactory.setTargetSource(targetSource);
// 自定义ProxyFactory,空方法,留给子类实现
customizeProxyFactory(proxyFactory);
// 用来控制proxyFactory被配置之后,是否还允许修改通知。默认值为false(即在代理被配置之后,不允许修改代理类的配置)
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 2.使用proxyFactory获取代理
return proxyFactory.getProxy(getProxyClassLoader());
}
2.使用 proxyFactory 获取代理,见代码块15。
代码块15:getProxy
public Object getProxy(ClassLoader classLoader) {
// 1.createAopProxy:创建AopProxy
// 2.getProxy(classLoader):获取代理对象实例
return createAopProxy().getProxy(classLoader);
}
1.createAopProxy:创建AopProxy,见代码块16。
2.getProxy(classLoader):获取代理对象实例,跟我们自己写的代理类似,JDK 动态代理见代码块18,CGLIB 代理见代码块19。
代码块16:createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
// 1.激活此代理配置
activate();
}
// 2.创建AopProxy
return getAopProxyFactory().createAopProxy(this);
}
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 1.判断使用JDK动态代理还是Cglib代理
// optimize:用于控制通过cglib创建的代理是否使用激进的优化策略。除非完全了解AOP如何处理代理优化,
// 否则不推荐使用这个配置,目前这个属性仅用于cglib代理,对jdk动态代理无效
// proxyTargetClass:默认为false,设置为true时,强制使用cglib代理,设置方式:<aop:aspectj-autoproxy proxy-target-class=“true” />
// hasNoUserSuppliedProxyInterfaces:config是否存在代理接口或者只有SpringProxy一个接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// 拿到要被代理的对象的类型
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
// TargetSource无法确定目标类:代理创建需要接口或目标。
throw new AopConfigException("TargetSource cannot determine target class: " +
“Either an interface or a target is required for proxy creation.”);
}
// 要被代理的对象是接口 || targetClass是Proxy class
// 当且仅当使用getProxyClass方法或newProxyInstance方法动态生成指定的类作为代理类时,才返回true。
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
// JDK动态代理,这边的入参config(AdvisedSupport)实际上是ProxyFactory对象
// 具体为:AbstractAutoProxyCreator中的proxyFactory.getProxy发起的调用,在ProxyCreatorSupport使用了this作为参数,
// 调用了的本方法,这边的this就是发起调用的proxyFactory对象,而proxyFactory对象中包含了要执行的的拦截器
return new JdkDynamicAopProxy(config);
}
// Cglib代理
return new ObjenesisCglibAopProxy(config);
} else {
// JDK动态代理
return new JdkDynamicAopProxy(config);
}
}
这边创建 AopProxy 的参数 config(AdvisedSupport)实际上是代码块14中的 proxyFactory 对象。
具体为:AbstractAutoProxyCreator 中的 proxyFactory.getProxy 发起的调用,在 ProxyCreatorSupport 使用了 this 作为参数调用了本方法,这边的 this 就是发起调用的 proxyFactory对象,而 proxyFactory 对象中包含了要执行的的拦截器(Advisor)。
无论是创建 JDK 动态代理还是 CGLIB 代理,都会传入 config 参数,该参数会被保存在 advised(AdvisedSupport)变量中,见代码块17。
代码块17:JDK 动态代理、CBLIB 代理构造函数
// JdkDynamicAopProxy.java
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”);
}
// config赋值给advised
this.advised = config;
}
// ObjenesisCglibAopProxy.java
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
}
// CglibAopProxy.java
public CglibAopProxy(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;
this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}
代码块18:JdkDynamicAopProxy#getProxy
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
// 1.拿到要被代理对象的所有接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 2.通过classLoader、接口、InvocationHandler实现类,来获取到代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
最终,通过 JDK 动态代理的类被调用时,会走到 JdkDynamicAopProxy#invoke 方法。
代码块19:CglibAopProxy#getProxy
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
try {
// 1.拿到要代理目标类
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, “Target class must be available for creating a CGLIB proxy”);
// proxySuperClass默认为rootClass
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
// 如果rootClass是被Cglib代理过的,获取rootClass的父类作为proxySuperClass
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
// 将父类的接口也添加到advised的interfaces属性
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
// 2.校验proxySuperClass,主要是校验方法是否用final修饰、跨ClassLoader的包可见方法,如果有将警告写入日志
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer…
// 3.创建和配置Cglib Enhancer
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// superclass为被代理的目标类proxySuperClass,通过名字可以看出,生成的代理类实际上是继承了被代理类
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 4.获取所有要回调的拦截器
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
// 在上面调用getCallbacks之后,此时仅填充fixedInterceptorMap
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
// 5.生成代理类并创建代理实例,返回代理实例
return createProxyClassAndInstance(enhancer, callbacks);
} catch (CodeGenerationException ex) {
throw new AopConfigException(“Could not generate CGLIB subclass of class [” +
this.advised.getTargetClass() + "]: " +
“Common causes of this problem include using a final class or a non-visible class”,
ex);
} catch (IllegalArgumentException ex) {
throw new AopConfigException(“Could not generate CGLIB subclass of class [” +
this.advised.getTargetClass() + "]: " +
“Common causes of this problem include using a final class or a non-visible class”,
ex);
最后
即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!
我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:
Dubbo面试专题
JVM面试专题
Java并发面试专题
Kafka面试专题
MongDB面试专题
MyBatis面试专题
MySQL面试专题
Netty面试专题
RabbitMQ面试专题
Redis面试专题
Spring Cloud面试专题
SpringBoot面试专题
zookeeper面试专题
常见面试算法题汇总专题
计算机网络基础专题
设计模式专题
第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!**
一共有20个知识点专题,分别是:
Dubbo面试专题
[外链图片转存中…(img-RCjkgosH-1715007365227)]
JVM面试专题
[外链图片转存中…(img-MhUzx2LW-1715007365228)]
Java并发面试专题
[外链图片转存中…(img-tFIQqDih-1715007365228)]
Kafka面试专题
[外链图片转存中…(img-PkKsvrbx-1715007365228)]
MongDB面试专题
[外链图片转存中…(img-sPeIbdqC-1715007365229)]
MyBatis面试专题
[外链图片转存中…(img-HJjychh7-1715007365229)]
MySQL面试专题
[外链图片转存中…(img-N63gkygp-1715007365229)]
Netty面试专题
[外链图片转存中…(img-h4yKgwuo-1715007365229)]
RabbitMQ面试专题
[外链图片转存中…(img-53iad3JQ-1715007365230)]
Redis面试专题
[外链图片转存中…(img-8ggofIUX-1715007365230)]
Spring Cloud面试专题
[外链图片转存中…(img-zduSr6jj-1715007365230)]
SpringBoot面试专题
[外链图片转存中…(img-sYAP4rfN-1715007365231)]
zookeeper面试专题
[外链图片转存中…(img-KHeaLVRS-1715007365231)]
常见面试算法题汇总专题
[外链图片转存中…(img-fjyANYdC-1715007365231)]
计算机网络基础专题
[外链图片转存中…(img-BYhNCn5q-1715007365232)]
设计模式专题
[外链图片转存中…(img-UcZ7dPNX-1715007365232)]