Aop
是什么AOP
(Aspect-Oriented Programming
,面向切面编程),可以说是 OOP
的补充和完善。OOP
引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP
则显得无能为力。OOP
允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切代码
面向切面编程,核心原理是使用动态代理模式在方法执行前后或出现异常时加入相关逻辑
aop
的使用场景Authentication
权限的处理Cache
缓存的处理Transactions
事务的处理Performance optimization
性能的优化等aop
相关概念Pointcut
:指定一个通知将被引发的一系列连接点的集合。AOP
框架必须允许开发者指定切入点:例如,使用正则表达式。spring
定义了 Pointcut
接口,用来组合MethodMatcher
和 ClassFilter
,可以通过名字很清楚的理解,MethodMatcher
是用来检查目标类的方法是否可以被应用此通知,而 ClassFilter
是用来检查 Pointcut
是否应该应用到目标类上Joinpoint
:程序执行过程中明确的点,如方法的调用或特定的异常被抛出Advice
:在特定的连接点,AOP
框架执行的动作。各种类型的通知包括 around、before
和 throws
通知。许多 AOP
框架包括 spring
都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。spring
中定义了四个 advice
:BeforeAdvice, AfterAdvice, ThrowAdvice,DynamicIntroductionAdvice
Aspect
:一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是 J2EE
应用中一个很好的横切关注点例子。方面用 spring
的 Advisor
或拦截器实现Weaving
:组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ
编译器),也可以在运行时完成spring aop
的简单实现引入 maven
依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.3.RELEASEversion>
parent>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
创建接口及其实现类
public interface Person {
void say();
}
public class Student implements Person{
public void say(){
System.out.println("这是一个苦逼的程序员");
}
}
创建切面类
@Aspect
public class AspectJTest {
@Pointcut("execution(* *.say(..))")
public void test(){}
@Before("test()")
public void before(){
System.out.println("before test..");
}
@After("test()")
public void after(){
System.out.println("after test..");
}
@Around("test()")
public Object around(ProceedingJoinPoint p){
System.out.println("before1");
Object o = null;
try {
o = p.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("after1");
return o;
}
}
测试类
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Person bean2 = (Person)ac.getBean("student");
bean2.say();
}
}
测试结果
before1
before test..
这是一个苦逼的程序员
after1
after test..
spring aop
源码解读读源码之前
在使用 ApplicationContext
相关实现类加载 bean
的时候,会对所有单例且非懒加载的 bean
,在构造 ApplicationContext
的时候就会初始化好这些 bean
,而不会等到使用的时候才去初始化。这也就是单例 bean
默认非懒加载的应用
结合以上,被代理后的 bean
,实际在 ApplicationContext
构造完成之后就已经被创建完成,getBean()
的操作直接从一级缓存 singletonObjects
中获取即可
beanPostProcessor
和 beanFactoryPostProcessor
beanPostProcessor
接口: bean
后置处理器。beanPostProcessor
能在 spring
容器实例化 bean
之后,bean
初始化前或后对 bean
做一些修改。而 aop
的功能实现正式基于此,在 bean
初始化后创建针对该 bean
的 proxy
,然后返回给用户该 proxy
beanFactoryPostProcessor
接口:beanFactoryPostProcessor
接口是针对 bean
容器的,它的实现类可以在当前 spring
容器加载 bean
定义后,bean
实例化之前修改 bean
的定义属性,达到影响之后实例化 bean
的效果
spring
中单例 bean
的初始化主要过程
createBeanInstance
:实例化,其实也就是调用对象的构造方法实例化对象populateBean
:填充属性,这一步主要是多 bean
的依赖属性进行填充initializeBean
:初始化,执行该 bean
的一些初始化方法寻找 aop
注解对应的解析器
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());// 就是该段代码
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
AspectJAutoProxyBeanDefinitionParser
对应的行为
public class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 1.注册proxy creator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
...
// registerAspectJAnnotationAutoProxyCreatorIfNecessary()
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册行为主要内容
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
// registerAspectJAnnotationAutoProxyCreatorIfNecessary()
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
// 主要就是为了注册AnnotationAwareAspectJAutoProxyCreator类
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
// 注册类相关代码
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 类似于我们在使用BeanFactory.getBean()时候的操作,生成一个RootBeanDefinition,然后放入map中
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
通过以上的代码分析,可知 AspectJAutoProxyBeanDefinitionParser
主要的功能就是将 AnnotationAwareAspectJAutoProxyCreator
注册到 spring
容器中,把 bean
交给 spring
去托管
分析 AnnotationAwareAspectJAutoProxyCreator
主要行为
通过查看 AnnotationAwareAspectJAutoProxyCreator
的类层次结构,可知,其实现了 beanPostProcessor
接口,实现类为 AbstractAutoProxyCreator
AbstractAutoProxyCreator
类主要方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
// 主要看这个方法,在 bean 初始化之后对生产出的 bean 进行包装
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 意思就是如果该类有 advice 则创建 proxy,
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 1.通过方法名也能简单猜测到,这个方法就是把 bean 包装为 proxy 的主要方法,
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
// 2.返回该 proxy 代替原来的 bean
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取提前访问指定bean的引用,用于解析循环依赖。在目标bean实例完全初始化之前调用
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
AspectJAutoProxyBeanDefinitionParser
类将AnnotationAwareAspectJAutoProxyCreator
注册到 spring
容器中AnnotationAwareAspectJAutoProxyCreator
类的 postProcessAfterInitialization()
方法将所有有 advice
的 bean
重新包装成 proxy
创建 proxy
过程分析
通过之前的代码结构分析,我们知道所有的 bean
在返回给用户使用之前都需要经过 AnnotationAwareAspectJAutoProxyCreator
类的 postProcessAfterInitialization()
方法,而该方法的主要作用也就是将所有拥有 advice
的 bean
重新包装为 proxy
,那么我们接下来直接分析这个包装为 proxy
的方法即可,看一下 bean
如何被包装为 proxy
,proxy
在被调用方法时,是具体如何执行的
以下是 AbstractAutoProxyCreator.wrapIfNecessary(Object bean, String beanName, Object cacheKey)
中的 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,proxy 的生产主要就是在 proxyFactory 做的
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 2.将当前 bean 适合的 advice,重新封装下,封装为 Advisor 类,然后添加到ProxyFactory 中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 3.调用 getProxy 获取 bean 对应的 proxy
return proxyFactory.getProxy(getProxyClassLoader());
}
创建何种类型的Proxy
?JDKProxy
还是 CGLIBProxy
?
// getProxy()方法
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
// createAopProxy()方法就是决定究竟创建何种类型的proxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 关键方法 createAopProxy()
return getAopProxyFactory().createAopProxy(this);
}
// createAopProxy()
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 1.config.isOptimize()是否使用优化的代理策略,目前使用与CGLIB
// config.isProxyTargetClass() 是否目标类本身被代理而不是目标类的接口
// hasNoUserSuppliedProxyInterfaces()是否存在代理接口
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.");
}
// 2.如果目标类是接口或者是代理类,则直接使用 JDKproxy
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 3.其他情况则使用 CGLIBproxy
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
getProxy()
方法
由上面可知,通过 createAopProxy()
方法来确定具体使用何种类型的 Proxy
针对于该示例,我们具体使用的为 JdkDynamicAopProxy
,下面来看下JdkDynamicAopProxy.getProxy()
方法
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable// JdkDynamicAopProxy类结构,由此可知,其实现了InvocationHandler,则必定有invoke方法,来被调用,也就是用户调用bean相关方法时,此invoke()被真正调用
// getProxy()
public Object getProxy(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);
// JDK proxy 动态代理的标准用法
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
invoke()
方法
以上的代码模式可以很明确的看出来,使用了 JDK
动态代理模式,真正的方法执行在 invoke()
方法里,下面我们来看下该方法,来看下 bean
方法如何被代理执行的
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
// 1.以下的几个判断,主要是为了判断 method 是否为 equals、hashCode 等 Object 的方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 2.获取当前 bean 被拦截方法链表
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 3.如果为空,则直接调用 target 的 method
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
// 4.不为空,则逐一调用 chain 中的每一个拦截方法的 proceed
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
...
return retVal;
}
...
}
拦截方法真正被执行调用 invocation.proceed()
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
依次遍历拦截器链的每个元素,然后调用其实现,将真正调用工作委托给各个增强器
spring aop
源码小结纵观以上过程可知:实际就是为 bean
创建一个 proxy
,JDKproxy
或者CGLIBproxy
,然后在调用 bean
的方法时,会通过 proxy
来调用 bean
方法
重点过程可分为:
AspectJAutoProxyBeanDefinitionParser
类将AnnotationAwareAspectJAutoProxyCreator
注册到 spring
容器中AnnotationAwareAspectJAutoProxyCreator
类的 postProcessAfterInitialization()
方法将所有有 advice
的 bean
重新包装成 proxy
bean
方法时通过 proxy
来调用,proxy
依次调用增强器的相关方法,来实现方法切入参考:https://blog.csdn.net/qq_26323323/article/details/81012855