public T getBean(String beanName) {
return (T) beanCache.get(beanName);
}
/**
- 获取对应类的接口
- @param classes 要获取的类对象
- @return 该类对象的接口
*/
private Class<?>[] getInterfaces(Class classes) {
return classes.getInterfaces();
}
/**
- 内部是否存在需要被拦截的方法对象
- @param targetClass 目标类对象
- @return 返回是否需要代理
*/
private boolean hasProxy(Class targetClass) {
//获取所有的方法
Method[] declaredMethods = targetClass.getDeclaredMethods();
for (Method method : Arrays.asList(declaredMethods)) {
//获取方法上的注解
Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
//当方法存在注释的时候 开始判断是否方法需要被代理
if (declaredAnnotations != null && declaredAnnotations.length > 0) {
for (Annotation annotation : Arrays.asList(declaredAnnotations)) {
//如果解析规则存在这个注解就返回true
if (proxyRule.containsKey(annotation.annotationType().getName())) {
return true;
}
}
}
}
return false;
}
/**
- 解析切面类
*/
private void parseAspectjClass() throws IllegalAccessException, InstantiationException {
for (Class aClass : aspectjClassCache) {
//获取切面的所有方法
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method method : Arrays.asList(declaredMethods)) {
//寻找携带MyAround注解的切面方法
MyAround myAroundAnntation = method.getAnnotation(MyAround.class);
if (myAroundAnntation != null) {
//拿到切点标志 也就是未来切点的方法
Class<? extends Annotation> targetClassAnnotation
= myAroundAnntation.targetClass();
//实例化切面
Object proxyTarget = aClass.newInstance();
//创建调用链实体
ProxyChain proxyChain = new ProxyChain(method, proxyTarget);
//构建对应规则的调用链
String classAnnotationName = targetClassAnnotation.getName();
if (proxyRule.containsKey(classAnnotationName)) {
proxyRule.get(classAnnotationName).add(proxyChain);
} else {
List proxyChains = new ArrayList<>();
proxyChains.add(proxyChain);
proxyRule.put(classAnnotationName, proxyChains);
}
}
}
}
}
}
具体的逻辑介绍,看文中注释,此时我们的AOP就开发完了,赶紧,去测一下!
6.开发一个通知注解
这个注解是为了标识那些方法需要被拦截的!
package simulation.aop.system;
import java.lang.annotation.*;
/**
- 模拟AOP通过注解方式添加拦截器
- @author huangfu
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAopAnnotation {
}
7.开发一个切面
package simulation.aop.my;
import simulation.aop.system.MyAopAnnotation;
import simulation.aop.system.MyAround;
import simulation.aop.system.MyProceedingJoinPoint;
import java.lang.reflect.InvocationTargetException;
/**
- 定义一个切面
- @author huangfu
*/
public class MyAspect {
/**
- 拦截所有方法上携带 MyAopAnnotation 注解的方法
- @param joinPoint
- @return
- @throws InvocationTargetException
- @throws IllegalAccessException
*/
@MyAround(targetClass = MyAopAnnotation.class)
public Object testAspect(MyProceedingJoinPoint joinPoint) throws InvocationTargetException, IllegalAccessException {
long startTime = System.currentTimeMillis();
//方法放行
Object proceed = joinPoint.proceed(joinPoint.getArgs());
long endTime = System.currentTimeMillis();
System.out.println(“总共用时:”+(endTime - startTime));
return proceed;
}
/**
- 拦截所有方法上携带 MyAopAnnotation 注解的方法
- @param joinPoint
- @return
- @throws InvocationTargetException
- @throws IllegalAccessException
*/
@MyAround(targetClass = MyAopAnnotation.class)
public Object testAspect2(MyProceedingJoinPoint joinPoint) throws InvocationTargetException, IllegalAccessException {
long startTime = System.currentTimeMillis();
//方法放行
Object proceed = joinPoint.proceed(joinPoint.getArgs());
long endTime = System.currentTimeMillis();
System.out.println(“总共用时:”+(endTime - startTime));
return proceed;
}
}
8.开发一个接口和一个实现类
package simulation.aop.my;
/**
- @author huangfu
/
public interface TestService {
/* - 打印一句话 拦截方法
- @param msg 返回信息
/
String print(String msg) throws InterruptedException;
/* - 普通方法 不拦截
**/
void sendUser();
}
package simulation.aop.my;
import simulation.aop.system.MyAopAnnotation;
/**
- 实现类
- @author huangfu
*/
public class TestServiceImpl implements TestService {
@MyAopAnnotation
@Override
public String print(String msg) throws InterruptedException {
System.out.println(“我执行了,参数是:”+msg);
Thread.sleep(5000);
return msg;
}
@Override
public void sendUser() {
System.out.println(“----发送信息—”);
}
}
9.最终测试
package simulation.aop;
import simulation.aop.my.TestService;
import simulation.aop.system.BeanUtil;
public class TestMyProxy {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, InterruptedException {
BeanUtil beanUtil = new BeanUtil();
beanUtil.initBean();
TestService testService = beanUtil.getBean(“testService”);
System.out.println(testService.print(“wqewqeqw”));
testService.sendUser();
}
}
10.结果
当然,肯定是成功的,但是写到这我慌了,为什么?现在就已经超过1w字了,源码部分还一个没动,天哪,我得去前面加个:不想看自己实现部分就跳过的提示!
三、Spring AOP源码学习
先看一张图,找到入口方法,我们好继续看源码:
第一列【万字长文,助你深度遨游Spring循环依赖源码实现!】说的很详细,我么从第二列开始说起:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
…忽略不必要代码…
if (mbd == null || !mbd.isSynthetic()) {
//调用这个bean 后置处理器的前置处理器 {@link BeanPostProcessor#postProcessBeforeInitialization()}
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//回调初始化方法
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()) {
//回调bean后置处理器的后置方法 {@link BeanPostProcessor#postProcessAfterInitialization()}
//这里也是AOP完成装载的地方,这一步也就到达了一个类从正常的类变成bean的最后一步
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
在调用初始化方法后,会回调BeanPostProcessors
的postProcessAfterInitialization
方法完成AOP的加载,我们进入到:applyBeanPostProcessorsAfterInitialization
方法:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//AOP的后置处理器被
//{@link org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization} 拦截
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
在这里,Spring会扫描所有的BeanPostProcessor
实现类,然后调用全部的postProcessAfterInitialization
方法,而AOP就是再一个叫做AbstractAutoProxyCreator
的类处理的,我们进入到org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
方法:
/**
- 如果bean被子类标识为要代理的bean,则使用配置的拦截器创建代理。
- @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//这里获取缓存的key然后从下面去取 什么时候缓存的呢?
//还记得为了解决循环依赖而引进的三级缓存不,明明二级缓存就能够解决,但是偏偏使用了三级缓存,而且三级缓存还是使用了一个工厂
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getEarlyBeanReference 没错这个方法再
//使用工厂返回对应的代理对象的时候,
//会调用org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.getEarlyBeanReference
//缓存一份自己的对象,这里就直接获取了
//这样再三级缓存进行返回了动态代理之后这里就不进行AOP的逻辑了 直接返回已经被三级缓存处理好额bean
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//这里是判断之前存储的AOP代理类是不是和创建好的bean不一致,如果一致就证明这个bean就已经是代理类了不需要走后续的AOP逻辑了
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//如果判断需要代理则执行AOP代理的包装逻辑
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
当判断该类需要被代理了,就进入到wrapIfNecessary
方法:
/**
- 必要时包装给定的bean,即是否有资格被代理。
- @param bean 原始bean实例
- @param beanName 豆的名字
- @param cacheKey 用于元数据访问的缓存键
- @return 包装Bean的代理,或按原样封装Raw Bean实例
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//如果已经处理过(targetSourcedBeans存放已经增强过的bean)
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
////advisedBeans的key为cacheKey,value为boolean类型,表示是否进行过代理
//如果设置了不允许代理,就直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//如果是本身就是AOP类 比如加了 @Asptj的类等一些基础设置会跳过不做代理,同时会将该类标注为不允许代理
//Advice、Pointcut、Advisor、AopInfrastructureBean
//设置了跳过 但是这个我需要后续取看
// TODO 不是这次看到主要代码 以后看
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//这里就是寻找这个bean的切点的 寻找对应的AOP代理
//获取当前对象所有适用的Advisor.找到所有切点是他的对应的@Aspect注解的类
//注意这里会返回该bean对应的所有的切面
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
//如果是允许代理的话
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//这一步是主要逻辑,创建一个代理对象 参数为:类的类对象 bean的名称 代理类的信息(位置,切点等信息) bean对象
Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
//如果查询出该类不允许被代理,将该bean 修改为不可代理!
this.advisedBeans.put(cacheKey, Boolean.FALSE);
//返回原始的Bean对象
return bean;
}
我们寻找到这个bean对应所有的切面方法,然后进入到createProxy
方法却具体的创建代理对象:
/**
- 为给定的bean创建一个AOP代理。
- @param beanClass bean的类型
- @param beanName bean的名字
- @param specificInterceptors 一组拦截器信息
- 特定于此bean(可以为空,但不能为null)
- @param targetSource 代理的对象
- 已经预先配置为访问Bean
- @return Bean的AOP代理
- @see #buildAdvisors
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//判断beanFactory的类型
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
//提前暴露这个bean是一个代理的类 如何设置呢?
//就是再该bean的bd下面设置一个代理信息
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建一个代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
//设置初始化参数
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
//正常的代理逻辑 判断设置一些代理参数
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//包装代理信息 切点信息包装
//这里是把所有的切面信息包装成了Advisor方便设置进工厂
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//向工厂设置代理切点信息
proxyFactory.addAdvisors(advisors);
//设置代理的目标类的包装类 嘿嘿嘿
proxyFactory.setTargetSource(targetSource);
//空方法 Spring没做实现 扩展点
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//真正代理逻辑 这里主要是获取一个真正代理 参数是类加载器
return proxyFactory.getProxy(getProxyClassLoader());
}
进入到getProxy
方法:
/**
- 根据此工厂中的设置创建一个新的代理。
-
可以反复调用。如果我们添加了效果会有所不同 或删除的接口。可以添加和删除拦截器。
-
使用给定的类加载器(如果需要创建代理)。
- @param classLoader 类加载器以创建代理 (或{@code null}为低级代理工具的默认值)
- @return 代理对象
*/
public Object getProxy(@Nullable ClassLoader classLoader) {
//createAopProxy返回使用的代理类型
//getProxy使用返回的代理类型创建代理对象
return createAopProxy().getProxy(classLoader);
}
这里实际上就是我们上述图示上说的判断代理类型是jdk还是cglib的地方,首先我们分成两部分看:进入到createAopProxy()
方法:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//使用之前创建的工厂选取一个代理方式 究竟是jdk还是cglib
return getAopProxyFactory().createAopProxy(this);
}
不做太多解释,直接到createAopProxy(this)
方法:
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//三个条件
//1.设置了优化
//2.proxyTargetClass 前面设置的
//{@link org.springframework.aop.framework.ProxyProcessorSupport.evaluateProxyInterfaces} 设置的是否有接口 没有接口就为true
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后
很多程序员,整天沉浸在业务代码的 CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。
我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。
不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
且后续会持续更新**
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-gtlr0v56-1712694042373)]
最后
很多程序员,整天沉浸在业务代码的 CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。
我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。
不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-ESUbj6HB-1712694042373)]