- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
Spring AOP框架的代码结构组织得不可为不好,良好的面向对象的编程思想,其中很有一部分得益于它对代码的结构的把控。良好的封装、分层、隔离。而在其中起到重要作用的,便是本文要盘点的一些工具类。
Spring框架的工具类,其实它是分为内部工具类和外部工具类的。如果是外部工具类,那是可以给调用者使用的,如果是内部工具类,那它一般都是在Spring的流程内部使用。
public interface HelloService {
Object hello();
}
public class HelloServiceImpl implements HelloService{
@Override
public Object hello() {
System.out.println("HelloServiceImpl is invoked");
return "hello world";
}
}
public class AopUtilMain {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new HelloServiceImpl());
proxyFactory.addAdvice((MethodBeforeAdvice)(method, args1, target)->{
System.out.println("前置通知~~~");
});
HelloService helloService = (HelloService) proxyFactory.getProxy();
helloService.hello();
System.out.println(helloService.getClass().getName());
}
}
测试:
该工具类是Spring非常重要的一个工具类。显然它是一个外部工具类,我们平时若想要对AOP做一些判断、处理,也是可议使用此工具类的。
public abstract class AopUtils {
/**
当前对象是否是代理类,可能被jdk或者cglib动态代理
*/
public static boolean isAopProxy(@Nullable Object object) {
return (object instanceof SpringProxy && (Proxy.isProxyClass(object.getClass()) ||
object.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)));
}
/**
是否是jdk动态代理
*/
public static boolean isJdkDynamicProxy(@Nullable Object object) {
return (object instanceof SpringProxy && Proxy.isProxyClass(object.getClass()));
}
/**
是否是cglib动态代理
*/
public static boolean isCglibProxy(@Nullable Object object) {
return (object instanceof SpringProxy &&
object.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR));
}
/**
如果传入的对象是代理对象则返回目标对象的类型,否则返回传入对象的class类型
*/
public static Class<?> getTargetClass(Object candidate) {
Assert.notNull(candidate, "Candidate object must not be null");
Class<?> result = null;
//TargetClassAware提供了暴露目标对象类型的api
if (candidate instanceof TargetClassAware) {
result = ((TargetClassAware) candidate).getTargetClass();
}
if (result == null) {
//是否是被cglib代理的对象,如果是返回代理对象的父类类型即目标对象的class类型
//否在返回当前对象本身的类型
result = (isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
}
return result;
}
/**
method在targetType类和其父接口上是否存在,存在就返回
这里targetType通常是代理类
*/
public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {
if (targetType == null) {
return method;
}
//MethodIntrospector.selectInvocableMethod是去寻找targetType类中是否存在method方法,如果不存在在去targetType
//的父接口中寻找是否存在,存在即返回,否在抛出异常
Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
//当前方法如果是私有的并且是非静态的并且是targetType是代理类
if (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) &&
SpringProxy.class.isAssignableFrom(targetType)) {
throw new IllegalStateException(String.format(
"Need to invoke method '%s' found on proxy for target class '%s' but cannot " +
"be delegated to target bean. Switch its visibility to package or protected.",
method.getName(), method.getDeclaringClass().getSimpleName()));
}
//返回找到的这个方法
return methodToUse;
}
//四个特殊方法的判断
public static boolean isEqualsMethod(@Nullable Method method) {
return ReflectionUtils.isEqualsMethod(method);
}
public static boolean isHashCodeMethod(@Nullable Method method) {
return ReflectionUtils.isHashCodeMethod(method);
}
public static boolean isToStringMethod(@Nullable Method method) {
return ReflectionUtils.isToStringMethod(method);
}
public static boolean isFinalizeMethod(@Nullable Method method) {
return (method != null && method.getName().equals("finalize") &&
method.getParameterCount() == 0);
}
/**
Given a method, which may come from an interface, and a target class used in the current AOP invocation, find the corresponding target method if there is one. E.g. the method may be IFoo.bar() and the target class may be DefaultFoo. In this case, the method may be DefaultFoo.bar(). This enables attributes on that method to be found.
NOTE: In contrast to ClassUtils.getMostSpecificMethod, this method resolves Java 5 bridge methods in order to retrieve attributes from the original method definition.
*/
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
Class<?> specificTargetClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null);
Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, specificTargetClass);
// If we are dealing with method with generic parameters, find the original method.
return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
}
public static boolean canApply(Pointcut pc, Class<?> targetClass) {
return canApply(pc, targetClass, false);
}
/**
给定的切入点可以完全应用于给定的类吗?
asIntroductions – whether or not the advisor chain for this bean includes any introductions
*/
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//先从类级别进行过滤
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
//再从方法级别进行过滤
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
//目标对象如果不是jdk代理类
if (!Proxy.isProxyClass(targetClass)) {
//getUserClass会尝试去处理cglib代理的情况,返回代理类的父类类型即目标对象类型---cglib
classes.add(ClassUtils.getUserClass(targetClass));
}
//加入当前类实现的所有接口---jdk
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//遍历
for (Class<?> clazz : classes) {
//拿到当前类型的所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
//对每个方法挨个进行匹配
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
//IntroductionAdvisor只需要进行类级别过滤即可
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
//调用上面分析的重载canApply方法
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
//其他类型的advisor没有ponitcut,默认都可以应用
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass) {
return canApply(pc, targetClass, false);
}
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
/**
从传入的候选advisors集合中,寻找到能应用到当前calss上的增强器有哪些
*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
//如果是IntroductionAdvisor ,那么直接进行类级别过滤级别,调用canApply其中一个重载方法完成类级别的过滤
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
//如果发现满足类匹配的条件,加入候选增强器集合
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
//IntroductionAdvisor上面已经处理过了
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
//判断ponitcutAdvisor和其他类型的Advisor能否应用
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
/**
使用反射调用连接点上的方法
反射调用target上的method方法,传入方法参数args
*/
@Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.
try {
//确保私有方法也可以反射调用
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
}
public static void main(String[] args) {
HelloService helloService = getProxy(new HelloServiceImpl());
//===============演示AopUtils==================
// AopUtils.isAopProxy:是否是代理对象
System.out.println(AopUtils.isAopProxy(helloService)); // true
System.out.println(AopUtils.isJdkDynamicProxy(helloService)); // false
System.out.println(AopUtils.isCglibProxy(helloService)); // true
// 拿到目标对象
System.out.println(AopUtils.getTargetClass(helloService)); //class com.fsx.service.HelloServiceImpl
// selectInvocableMethod:方法@since 4.3 底层依赖于方法MethodIntrospector.selectInvocableMethod
// 只是在他技术上做了一个判断: 必须是被代理的方法才行(targetType是SpringProxy的子类,且是private这种方法,且不是static的就不行)
// Spring MVC的detectHandlerMethods对此方法有大量调用~~~~~
Method method = ClassUtils.getMethod(HelloServiceImpl.class, "hello");
System.out.println(AopUtils.selectInvocableMethod(method, HelloServiceImpl.class)); //public java.lang.Object com.fsx.service.HelloServiceImpl.hello()
// 是否是equals方法
// isToStringMethod、isHashCodeMethod、isFinalizeMethod 都是类似的
System.out.println(AopUtils.isEqualsMethod(method)); //false
// 它是对ClassUtils.getMostSpecificMethod,增加了对代理对象的特殊处理。。。
System.out.println(AopUtils.getMostSpecificMethod(method,HelloService.class));
}
从名字可以看出,这个是关于AOP配置的工具类。因为配置AOP的方式有多种(比如xml、注解等),此工具类就是针对不同配置,提供不同的工具方法的。
它的好处是不管什么配置,最终走底层逻辑都让归一了~~~~
类注释翻译:
该类是来管理自动代理创建器的注册
应该只注册一个自动代理创建者,但可以使用多个具体实现。
此类提供了一个简单的升级协议,允许调用者请求特定的自动代理创建者,并知道该创建者或其更强大的变体将被注册为后处理器。
public abstract class AopConfigUtils {
/**
* 这是注册自动代理创建器,默认的BeanName(若想覆盖,需要使用这个BeanName)
*/
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
/**
* 按照升级顺序 存储自动代理创建器(注意这里是升级的顺序 一个比一个强的)
*/
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
//这里每个自动代理创建器都对应一个优先级,优先级就是该自动代理创建器再集合中的下标,下标越大,优先级越高
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
// 这两个:注册的是`InfrastructureAdvisorAutoProxyCreator`
// 调用处为:AutoProxyRegistrar#registerBeanDefinitions(它是一个ImportBeanDefinitionRegistrar实现类)
// 而AutoProxyRegistrar使用处为CachingConfigurationSelector,和`@EnableCaching`注解有关
// 其次就是AopNamespaceUtils有点用,这个下面再分析
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
// 下面这两个是注入:AspectJAwareAdvisorAutoProxyCreator
// 目前没有地方默认调用~~~~和Aop的xml配置方案有关的
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
// 这个就是最常用的,注入的是:AnnotationAwareAspectJAutoProxyCreator 注解驱动的自动代理创建器
// `@EnableAspectJAutoProxy`注入进来的就是它了
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
// 这两个方法,很显然,就是处理注解的两个属性值
// proxyTargetClass:true表示强制使用CGLIB的动态代理
// exposeProxy:true暴露当前代理对象到线程上绑定
// 最终都会放到自动代理创建器得BeanDefinition 里面去~~~创建代理的时候会用到此属性值
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
//========上面的注册自动代理创建器IfNecessary之类的方法,最终都是调用了这里========
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//如果容器中包含了AUTO_PROXY_CREATOR_BEAN_NAME对应的beanName,那么此时再进行注册操作就需要根据优先级来判断是否需要进行覆盖
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
//拿到容器中现存的自动代理创建器
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
//当然要注册进容器的bean和容器中现存的bean的类型不能一样,否则不进行操作
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
//获取容器中已有的自动代理创建器的优先级
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
//获取要注册进容器的自动代理创建器的优先级
int requiredPriority = findPriorityForClass(cls);
//只有在优先级更大的情况下,才会覆盖成功
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//容器中还没有自动代理创建器,那么就直接把当前要注册进容器的自动代理创建器注册到容器中
// 绝大部分情况下都会走这里,new一个Bean定义信息出来,然后order属性值为HIGHEST_PRECEDENCE
// role是:ROLE_INFRASTRUCTURE属于Spring框架自己使用的Bean
// BeanName为:AUTO_PROXY_CREATOR_BEAN_NAME
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//注册beanDefinition
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
//优先级就是根据当前自动代理创建器在集合中的序号决定的
private static int findPriorityForClass(Class<?> clazz) {
return APC_PRIORITY_LIST.indexOf(clazz);
}
private static int findPriorityForClass(@Nullable String className) {
for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
Class<?> clazz = APC_PRIORITY_LIST.get(i);
if (clazz.getName().equals(className)) {
return i;
}
}
throw new IllegalArgumentException(
"Class name [" + className + "] is not a known auto-proxy creator class");
}
}
由于AopConfigUtils 并没有公开可以向APC_PRIORITY_LIST 中添加元素的方法,因此我们只能注册他规定的三种自动代理创建器
备注:请尽量不要自定义自动代理创建器,也不要轻易使用低级别的创建器,若你对原理不是非常懂的话,慎重
这个从名字可以看出,是处理Spring AOP命名空间的工具类。比如
xmlns:aop="http://www.springframework.org/schema/aop
处理这种xml里面的
<aop:config />
<aop:advice />
等这种。当然还有对proxy-target-class和expose-proxy的处理。因为接下来的重点都不在xml里,因此此处略过(最终它调用都是AopConfigUtils#XXXIfNecessary的方法,去注册不同的自动代理创建器的)
我理解成它是对org.springframework.aop.support.AopUtils的一个补充。
public abstract class AopProxyUtils {
// JDK 17 Class.isSealed() method available?
@Nullable
private static final Method isSealedMethod = ClassUtils.getMethodIfAvailable(Class.class, "isSealed");
/**
获取代理对象代理的目标对象
*/
@Nullable
public static Object getSingletonTarget(Object candidate) {
//如果传入的代理对象实现了Advised接口
if (candidate instanceof Advised) {
//拿到TargetSource
TargetSource targetSource = ((Advised) candidate).getTargetSource();
if (targetSource instanceof SingletonTargetSource) {
//拿到目标对象
return ((SingletonTargetSource) targetSource).getTarget();
}
}
return null;
}
/**
返回代理对象代理的目标对象的class类型
*/
public static Class<?> ultimateTargetClass(Object candidate) {
Assert.notNull(candidate, "Candidate object must not be null");
Object current = candidate;
Class<?> result = null;
//如果代理对象实现了TargetClassAware接口,可以通过该接口直接获取到目标对象的类型
while (current instanceof TargetClassAware) {
result = ((TargetClassAware) current).getTargetClass();
//拿到目标对象
current = getSingletonTarget(current);
}
if (result == null) {
//如果上面没能获取到结果
//代理类是否是被cglib代理,如果是的话,返回代理类的父类类型,否则返回代理类自身类型
result = (AopUtils.isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
}
return result;
}
/**
通过传入的aop配置,来决定最终代理对象需要实现的代理接口有哪些
*/
public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) {
return completeProxiedInterfaces(advised, false);
}
//decoratingProxy:代理对象是否要实现 DecoratingProxy接口
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
//从代理配置中拿到当前代理对象设置的需要代理的接口
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
//如果没有需要代理的接口
if (specifiedInterfaces.length == 0) {
// No user-specified interfaces: check whether target class is an interface.
//拿到目标对象的类型
Class<?> targetClass = advised.getTargetClass();
if (targetClass != null) {
//判断是否是接口,如果是,那么设置代理对象需要实现目标对象的接口
if (targetClass.isInterface()) {
advised.setInterfaces(targetClass);
}
//当前目标对象是否是jdk动态代理类型
else if (Proxy.isProxyClass(targetClass)) {
//如果是的话,拿到jdk动态代理类实现的接口,设置为需要实现的代理接口
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
//这边的+3,意味着下面可能需要实现额外的三个接口
List<Class<?>> proxiedInterfaces = new ArrayList<>(specifiedInterfaces.length + 3);
//jdk17的适配处理,这里先跳过
for (Class<?> ifc : specifiedInterfaces) {
// Only non-sealed interfaces are actually eligible for JDK proxying (on JDK 17)
if (isSealedMethod == null || Boolean.FALSE.equals(ReflectionUtils.invokeMethod(isSealedMethod, ifc))) {
proxiedInterfaces.add(ifc);
}
}
//判断SpringProxy接口是否已经加入了代理类需要实现的接口,没加入则加入
//即所有代理对象都会实现SpringProxy接口
if (!advised.isInterfaceProxied(SpringProxy.class)) {
proxiedInterfaces.add(SpringProxy.class);
}
//proxyConfig的opaque属性是否为true,该属性为true,则表示代理类不能强制转换为advised接口,默认为false,即代理类需要继承advised接口
//还有一点需要保证,就是Advised未被加入需要代理的接口数组中
if (!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)) {
proxiedInterfaces.add(Advised.class);
}
//decoratingProxy属性来确保代理类是否需要实现DecoratingProxy接口,该接口会暴露api来获取到代理对象代理的目标对象的类型
if (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)) {
proxiedInterfaces.add(DecoratingProxy.class);
}
//返回最终需要实现的代理接口集合
return ClassUtils.toClassArray(proxiedInterfaces);
}
/**
获取传入的代理对象实现的接口中,用户指定的代理接口,因为上面的方法我们已经看到了,可能需要额外实现三个接口
*/
public static Class<?>[] proxiedUserInterfaces(Object proxy) {
//拿到代理类已经实现的所有接口
Class<?>[] proxyInterfaces = proxy.getClass().getInterfaces();
int nonUserIfcCount = 0;
//判断下面三个接口实现了几个
if (proxy instanceof SpringProxy) {
nonUserIfcCount++;
}
if (proxy instanceof Advised) {
nonUserIfcCount++;
}
if (proxy instanceof DecoratingProxy) {
nonUserIfcCount++;
}
//行为额外新增加的三个接口,会放在数组尾部,因此从尾部嘎掉他们即可
Class<?>[] userInterfaces = Arrays.copyOf(proxyInterfaces, proxyInterfaces.length - nonUserIfcCount);
Assert.notEmpty(userInterfaces, "JDK proxy must implement one or more interfaces");
return userInterfaces;
}
/**
* Check equality of the proxies behind the given AdvisedSupport objects.
* Not the same as equality of the AdvisedSupport objects:
* rather, equality of interfaces, advisors and target sources.
*/
public static boolean equalsInProxy(AdvisedSupport a, AdvisedSupport b) {
return (a == b ||
(equalsProxiedInterfaces(a, b) && equalsAdvisors(a, b) && a.getTargetSource().equals(b.getTargetSource())));
}
/**
* Check equality of the proxied interfaces behind the given AdvisedSupport objects.
*/
public static boolean equalsProxiedInterfaces(AdvisedSupport a, AdvisedSupport b) {
return Arrays.equals(a.getProxiedInterfaces(), b.getProxiedInterfaces());
}
/**
* Check equality of the advisors behind the given AdvisedSupport objects.
*/
public static boolean equalsAdvisors(AdvisedSupport a, AdvisedSupport b) {
return a.getAdvisorCount() == b.getAdvisorCount() && Arrays.equals(a.getAdvisors(), b.getAdvisors());
}
/**
* Adapt the given arguments to the target signature in the given method,
* if necessary: in particular, if a given vararg argument array does not
* match the array type of the declared vararg parameter in the method.
* 方法参数类型适配
*/
static Object[] adaptArgumentsIfNecessary(Method method, @Nullable Object[] arguments) {
if (ObjectUtils.isEmpty(arguments)) {
return new Object[0];
}
if (method.isVarArgs()) {
if (method.getParameterCount() == arguments.length) {
Class<?>[] paramTypes = method.getParameterTypes();
int varargIndex = paramTypes.length - 1;
Class<?> varargType = paramTypes[varargIndex];
if (varargType.isArray()) {
Object varargArray = arguments[varargIndex];
if (varargArray instanceof Object[] && !varargType.isInstance(varargArray)) {
Object[] newArguments = new Object[arguments.length];
System.arraycopy(arguments, 0, newArguments, 0, varargIndex);
Class<?> targetElementType = varargType.getComponentType();
int varargLength = Array.getLength(varargArray);
Object newVarargArray = Array.newInstance(targetElementType, varargLength);
System.arraycopy(varargArray, 0, newVarargArray, 0, varargLength);
newArguments[varargIndex] = newVarargArray;
return newArguments;
}
}
}
}
return arguments;
}
}
JDK代理和CGLIB代理的获取代理对象方法都用使用到了该类中的方法:
// JDK代理的获取代理对象~~~
@Override
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);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
AopProxyUtils中的方法不多,但是其中的ultimateTargetClass和completeProxiedInterfaces方法确是Spring AOP中比较重要的方法,也给
包含用于获取有关当前 AOP 调用信息的静态方法的类。
如果 AOP 框架配置为公开当前代理(不是默认代理),则 currentProxy() 方法可用。它返回正在使用的 AOP 代理。目标对象或advice 可以使用它来进行advice 调用,就像在 EJB 中使用 getEJBObject() 一样。他们还可以使用它来查找advice configuration.。
Spring 的 AOP 框架默认不公开代理,因为这样做会降低性能。
此类中的功能可能由需要在调用时访问资源的目标对象使用。但是,如果有合理的替代方案,则不应使用此方法,因为它使应用程序代码依赖于 AOP 下的使用,尤其是 Spring AOP 框架。
public final class AopContext {
/**
与此线程关联的 AOP 代理的 ThreadLocal 持有者。
除非控制代理配置上的“exposeProxy”属性设置为“true”,否则将包含 null。
*/
private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");
private AopContext() {
}
/**
尝试返回当前的 AOP 代理。仅当调用方法已通过 AOP 调用,
并且 AOP 框架已设置为公开代理时,此方法才可用。否则,此方法将抛出 IllegalStateException。
*/
public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and " +
"ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.");
}
return proxy;
}
/**
通过 currentProxy() 方法使给定的代理可用。
请注意,调用者应注意适当地保留旧值。
*/
@Nullable
static Object setCurrentProxy(@Nullable Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);
}
else {
currentProxy.remove();
}
return old;
}
}
备注:这个工具类主要是和属性exposeProxy相关,让我们能够快捷的获取到AOP代理对象,而不是this对象。这个在事务不生效原因大解读的博文了得到了应用
为自动代理组件准备的工具类。主要用于框架内部使用(AbstractAutoProxyCreator)
public abstract class AutoProxyUtils {
// preserve:保护的 保留的
// determine:查明 测定
public static final String PRESERVE_TARGET_CLASS_ATTRIBUTE =
Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "preserveTargetClass");
public static final String ORIGINAL_TARGET_CLASS_ATTRIBUTE =
Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "originalTargetClass");
// 判断该beanName是否应该被代理
// `AbstractAutoProxyCreator`里就有判断是否能够被代理。 如果能够被代理,那就采用CGLIB的代理方式了
// 往里setAttr,目前只有`ConfigurationClassPostProcessor`对config配置类进行增强的时候
public static boolean shouldProxyTargetClass(
ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) {
if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
}
return false;
}
// 看看这个Bean定义的TargetClass
// 如果Bean定义信息里面有ORIGINAL_TARGET_CLASS_ATTRIBUTE这个字段,那就不用getType()了
// 以及ScopedProxyUtils创建和Scope有关的代理类的时候,其余地方都不会设置此属性
@Nullable
public static Class<?> determineTargetClass(
ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) {
if (beanName == null) {
return null;
}
if (beanFactory.containsBeanDefinition(beanName)) {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
Class<?> targetClass = (Class<?>) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE);
if (targetClass != null) {
return targetClass;
}
}
return beanFactory.getType(beanName);
}
//Expose the given target class for the specified bean, if possible
// 就是在它的Bean定义信息里面,设置一个ORIGINAL_TARGET_CLASS_ATTRIBUTE属性,然后吧targetClass类型放进去
// 也是子啊`AbstractAutoProxyCreator`创建代理的时候会这只进去的
static void exposeTargetClass(
ConfigurableListableBeanFactory beanFactory, @Nullable String beanName, Class<?> targetClass) {
if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
beanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass);
}
}
/**
根据 AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX 确定给定的 bean 名称是否指示“原始实例”,跳过任何代理尝试。
*/
static boolean isOriginalInstance(String beanName, Class<?> beanClass) {
//beanName如果以.ORIGINAL结尾,则不进行代理操作
if (!StringUtils.hasLength(beanName) || beanName.length() !=
beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {
return false;
}
return (beanName.startsWith(beanClass.getName()) &&
beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));
}
}
相比于AopUtils,AspectJAopUtils是专门针对于AspectJ advisors的工具类。(当然AspectJ也是当下的主流方式)
public abstract class AspectJAopUtils {
// Advisor 是否是前置通知类型~~~~(Advisor都持有一个advice嘛)
public static boolean isBeforeAdvice(Advisor anAdvisor) {
AspectJPrecedenceInformation precedenceInfo = getAspectJPrecedenceInformationFor(anAdvisor);
if (precedenceInfo != null) {
return precedenceInfo.isBeforeAdvice();
}
return (anAdvisor.getAdvice() instanceof BeforeAdvice);
}
// Advisor 是否是后置通知类型~~~~(Advisor都持有一个advice嘛)
public static boolean isAfterAdvice(Advisor anAdvisor) {
AspectJPrecedenceInformation precedenceInfo = getAspectJPrecedenceInformationFor(anAdvisor);
if (precedenceInfo != null) {
return precedenceInfo.isAfterAdvice();
}
return (anAdvisor.getAdvice() instanceof AfterAdvice);
}
//拿到AspectJ的优先信息:AspectJPrecedenceInformation
@Nullable
public static AspectJPrecedenceInformation getAspectJPrecedenceInformationFor(Advisor anAdvisor) {
if (anAdvisor instanceof AspectJPrecedenceInformation) {
return (AspectJPrecedenceInformation) anAdvisor;
}
Advice advice = anAdvisor.getAdvice();
if (advice instanceof AspectJPrecedenceInformation) {
return (AspectJPrecedenceInformation) advice;
}
return null;
}
}
同样的,它相对于AopProxyUtils,它只是专门处理AspectJ代理对象的工具类。
public abstract class AspectJProxyUtils {
// 只提供这么一个公共方法,但是这个方法都还是非常重要的。 Capable:有能力的
// 它在自动代理创建器`AspectJAwareAdvisorAutoProxyCreator#extendAdvisors`方法中有调用(重要~~~)
// 在AspectJProxyFactory#addAdvisorsFromAspectInstanceFactory方法中也有调用
// 它的作用:只要发现有AspectJ的Advisor存在,并且advisors还不包含有ExposeInvocationInterceptor.ADVISOR 那就在第一个位置上调添加一个ExposeInvocationInterceptor.ADVISOR
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
//只要发现当前增强器链存在AspectJAdvice,那么便尝试往advisors的中头部放入一个ExposeInvocationInterceptor
//该拦截器的作用是将当前MethodInvocation调用链放到ThreadLocal中
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
// 判断,该Advisor是否是AspectJ的的增强器
//这个方法也说明了AspectJExpressionPointcut,AbstractAspectJAdvice 和InstantiationModelAwarePointcutAdvisor 都是和AspectJ相关的类包括他们下面的子类
private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
...
}
某些通知内部会用到调用链对象,所以我们在执行的时候需要将调用链放在让所有通知都能获取到的一个地方,哪里呢?
放入当前线程的工作是由spring自动添加的一个外层环绕通知完成的,这里也解释了为什么spring会默认添加的一个最外层的通知
public final class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable {
/** 单例体现. */
public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();
/**
* Singleton advisor for this class. Use in preference to INSTANCE when using
* Spring AOP, as it prevents the need to create a new Advisor to wrap the instance.
*/
public static final Advisor ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
@Override
public String toString() {
return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
}
};
//存放当前MethodInvocation
private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<>("Current AOP method invocation");
//返回当前正在调用的MethodInvocation
public static MethodInvocation currentInvocation() throws IllegalStateException {
MethodInvocation mi = invocation.get();
if (mi == null) {
throw new IllegalStateException(
"No MethodInvocation found: Check that an AOP invocation is in progress and that the " +
"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +
"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! " +
"In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() " +
"must be invoked from the same thread.");
}
return mi;
}
/**
* Ensures that only the canonical instance can be created.
*/
private ExposeInvocationInterceptor() {
}
//
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
//当前线程的调用链更新
invocation.set(mi);
try {
//调用链执行---递归调用
return mi.proceed();
}
finally {
//最后还是会将恢复为最开始的MethodInvocation
invocation.set(oldInvocation);
}
}
@Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE + 1;
}
/**
* Required to support serialization. Replaces with canonical instance
* on deserialization, protecting Singleton pattern.
* <p>Alternative to overriding the {@code equals} method.
*/
private Object readResolve() {
return INSTANCE;
}
}
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
介绍篇 什么是MiniApis? MiniApis的特点和优势 MiniApis的应用场景 环境搭建 系统要求 安装MiniApis 配置开发环境 基础概念 MiniApis架构概述
我正在从“JavaScript 圣经”一书中学习 javascript,但我遇到了一些困难。我试图理解这段代码: function checkIt(evt) { evt = (evt) ? e
package com.fastone.www.javademo.stringintern; /** * * String.intern()是一个Native方法, * 它的作用是:如果字
您会推荐哪些资源来学习 AppleScript。我使用具有 Objective-C 背景的传统 C/C++。 我也在寻找有关如何更好地开发和从脚本编辑器获取更快文档的技巧。示例提示是“查找要编写脚本的
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
关闭。这个问题不符合 Stack Overflow guidelines 。它目前不接受答案。 想改善这个问题吗?更新问题,以便堆栈溢出为 on-topic。 6年前关闭。 Improve this
我是塞内加尔的阿里。我今年60岁(也许这是我真正的问题-笑脸!!!)。 我正在学习Flutter和Dart。今天,我想使用给定数据模型的列表(它的名称是Mortalite,请参见下面的代码)。 我尝试
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
学习 Cappuccino 的最佳来源是什么?我从事“传统”网络开发,但我对这个新框架非常感兴趣。请注意,我对 Objective-C 毫无了解。 最佳答案 如上所述,该网站是一个好地方,但还有一些其
我正在学习如何使用 hashMap,有人可以检查我编写的这段代码并告诉我它是否正确吗?这个想法是有一个在公司工作的员工列表,我想从 hashMap 添加和删除员工。 public class Staf
我正在尝试将 jQuery 与 CoffeScript 一起使用。我按照博客中的说明操作,指示使用 $ -> 或 jQuery -> 而不是 .ready() 。我玩了一下代码,但我似乎无法理解我出错
还在学习,还有很多问题,所以这里有一些。我正在进行 javascript -> PHP 转换,并希望确保这些做法是正确的。是$dailyparams->$calories = $calories;一条
我目前正在学习 SQL,以便从我们的 Magento 数据库制作一个简单的 RFM 报告,我目前可以通过导出两个查询并将它们粘贴到 Excel 模板中来完成此操作,我想摆脱 Excel 模板。 我认为
我知道我很可能会因为这个问题而受到抨击,但没有人问,我求助于你。这是否是一个正确的 javascript > php 转换 - 在我开始不良做法之前,我想知道这是否是解决此问题的正确方法。 JavaS
除了 Ruby-Doc 之外,哪些来源最适合获取一些示例和教程,尤其是关于 Ruby 中的 Tk/Tile?我发现自己更正常了 http://www.tutorialspoint.com/ruby/r
我只在第一次收到警告。这正常吗? >>> cv=LassoCV(cv=10).fit(x,y) C:\Python27\lib\site-packages\scikit_learn-0.14.1-py
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be
我是一名优秀的程序员,十分优秀!