做者:小傅哥
博客:https://bugstack.cnhtml
沉淀、分享、成长,让本身和他人都能有所收获!😄
为何,你的代码老是糊到猪圈上?
java
🎙怎么办,知道你在互联网,不知道你在哪一个大厂。知道你在加班,不知道你在和哪一个产品争辩。知道你在偷懒,不知道你要摸鱼到几点。知道你在搬砖,不知道你在盖哪一个猪圈。spring
当你特别辛苦夜以继日的完成着,天天、每周、每个月重复性的工做时,你能得到的成长是最小,获得的回报也是少的。留着最多的汗、拿着最少的钱数据库
可能你一激动开始看源码,但不知道看完的源码能用到什么地方。看设计模式,看的时候懂,但改本身的代码又下不去手。其实一方面是自己技术栈的知识面不足,另一方面是本身储备的代码也不够。最终也就致使根本无法把一些列的知识串联起来,就像你看了 HashMap,但也联想不到分库分表组件中的数据散列也会用到了 HashMap 中的扰动函数思想和泊松分布验证
、看了Spring 源码,也读不出来 Mybatis 是如何解决只定义 Dao 接口就能使用配置或者注解对数据库进行 CRUD 操做
、看来 JDK 的动态代理,也想不到 AOP 是如何设计的
。因此成体系学习,增强技术栈知识的完整性,才能更好的用上这些学习到的编码能力。express
到本章节咱们将要从 IOC 的实现,转入到关于 AOP(Aspect Oriented Programming
) 内容的开发。在软件行业,AOP 意为:面向切面编程,经过预编译的方式和运行期间动态代理实现程序功能功能的统一维护。其实 AOP 也是 OOP 的延续,在 Spring 框架中是一个很是重要的内容,使用 AOP 能够对业务逻辑的各个部分进行隔离,从而使各模块间的业务逻辑耦合度下降,提升代码的可复用性,同时也能提升开发效率。编程
关于 AOP 的核心技术实现主要是动态代理的使用,就像你能够给一个接口的实现类,使用代理的方式替换掉这个实现类,使用代理类来处理你须要的逻辑。好比:segmentfault
@Test public void test_proxy_class() { IUserService userService = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IUserService.class}, (proxy, method, args) -> "你被代理了!"); String result = userService.queryUserInfo(); System.out.println("测试结果:" + result); }
代理类的实现基本都你们都见过,那么有了一个基本的思路后,接下来就须要考虑下怎么给方法作代理呢,而不是代理类。另外怎么去代理全部符合某些规则的全部类中方法呢。若是能够代理掉全部类的方法,就能够作一个方法拦截器,给全部被代理的方法添加上一些自定义处理,好比打印日志、记录耗时、监控异常等。设计模式
在把 AOP 整个切面设计融合到 Spring 前,咱们须要解决两个问题,包括:如何给符合规则的方法作代理
,以及作完代理方法的案例后,把类的职责拆分出来
。而这两个功能点的实现,都是以切面的思想进行设计和开发。若是不是很清楚 AOP 是啥,你能够把切面理解为用刀切韭菜,一根一根切老是有点慢,那么用手(代理
)把韭菜捏成一把,用菜刀或者斧头这样不一样的拦截操做来处理。而程序中其实也是同样,只不过韭菜变成了方法,菜刀变成了拦截方法。总体设计结构以下图:架构
MethodInterceptor#invoke
,而不是直接使用 invoke 方法中的入参 Method method 进行 method.invoke(targetObj, args)
这块是整个使用时的差别。org.aspectj.weaver.tools.PointcutParser
处理拦截表达式 "execution(* cn.bugstack.springframework.test.bean.IUserService.*(..))"
,有了方法代理和处理拦截,咱们就能够完成设计出一个 AOP 的雏形了。small-spring-step-11 └── src ├── main │ └── java │ └── cn.bugstack.springframework │ ├── aop │ │ ├── aspectj │ │ │ └── AspectJExpressionPointcut.java │ │ ├── framework │ │ │ ├── AopProxy.java │ │ │ ├── Cglib2AopProxy.java │ │ │ ├── JdkDynamicAopProxy.java │ │ │ └── ReflectiveMethodInvocation.java │ │ ├── AdvisedSupport.java │ │ ├── ClassFilter.java │ │ ├── MethodMatcher.java │ │ ├── Pointcut.java │ │ └── TargetSource.java │ ├── beans │ │ ├── factory │ │ │ ├── config │ │ │ │ ├── AutowireCapableBeanFactory.java │ │ │ │ ├── BeanDefinition.java │ │ │ │ ├── BeanFactoryPostProcessor.java │ │ │ │ ├── BeanPostProcessor.java │ │ │ │ ├── BeanReference.java │ │ │ │ ├── ConfigurableBeanFactory.java │ │ │ │ └── SingletonBeanRegistry.java │ │ │ ├── support │ │ │ │ ├── AbstractAutowireCapableBeanFactory.java │ │ │ │ ├── AbstractBeanDefinitionReader.java │ │ │ │ ├── AbstractBeanFactory.java │ │ │ │ ├── BeanDefinitionReader.java │ │ │ │ ├── BeanDefinitionRegistry.java │ │ │ │ ├── CglibSubclassingInstantiationStrategy.java │ │ │ │ ├── DefaultListableBeanFactory.java │ │ │ │ ├── DefaultSingletonBeanRegistry.java │ │ │ │ ├── DisposableBeanAdapter.java │ │ │ │ ├── FactoryBeanRegistrySupport.java │ │ │ │ ├── InstantiationStrategy.java │ │ │ │ └── SimpleInstantiationStrategy.java │ │ │ ├── support │ │ │ │ └── XmlBeanDefinitionReader.java │ │ │ ├── Aware.java │ │ │ ├── BeanClassLoaderAware.java │ │ │ ├── BeanFactory.java │ │ │ ├── BeanFactoryAware.java │ │ │ ├── BeanNameAware.java │ │ │ ├── ConfigurableListableBeanFactory.java │ │ │ ├── DisposableBean.java │ │ │ ├── FactoryBean.java │ │ │ ├── HierarchicalBeanFactory.java │ │ │ ├── InitializingBean.java │ │ │ └── ListableBeanFactory.java │ │ ├── BeansException.java │ │ ├── PropertyValue.java │ │ └── PropertyValues.java │ ├── context │ │ ├── event │ │ │ ├── AbstractApplicationEventMulticaster.java │ │ │ ├── ApplicationContextEvent.java │ │ │ ├── ApplicationEventMulticaster.java │ │ │ ├── ContextClosedEvent.java │ │ │ ├── ContextRefreshedEvent.java │ │ │ └── SimpleApplicationEventMulticaster.java │ │ ├── support │ │ │ ├── AbstractApplicationContext.java │ │ │ ├── AbstractRefreshableApplicationContext.java │ │ │ ├── AbstractXmlApplicationContext.java │ │ │ ├── ApplicationContextAwareProcessor.java │ │ │ └── ClassPathXmlApplicationContext.java │ │ ├── ApplicationContext.java │ │ ├── ApplicationContextAware.java │ │ ├── ApplicationEvent.java │ │ ├── ApplicationEventPublisher.java │ │ ├── ApplicationListener.java │ │ └── ConfigurableApplicationContext.java │ ├── core.io │ │ ├── ClassPathResource.java │ │ ├── DefaultResourceLoader.java │ │ ├── FileSystemResource.java │ │ ├── Resource.java │ │ ├── ResourceLoader.java │ │ └── UrlResource.java │ └── utils │ └── ClassUtils.java └── test └── java └── cn.bugstack.springframework.test ├── bean │ ├── IUserService.java │ ├── UserService.java │ └── UserServiceInterceptor.java └── ApiTest.java
工程源码:公众号「bugstack虫洞栈」,回复:Spring 专栏,获取完整源码
app
AOP 切点表达式和使用以及基于 JDK 和 CGLIB 的动态代理类关系,如图 12-2
在实现 AOP 的核心功能以前,咱们先作一个代理方法的案例,经过这样一个能够归纳代理方法的核心全貌,可让你们更好的理解后续拆解各个方法,设计成解耦功能的 AOP 实现过程。
单元测试
@Test public void test_proxy_method() { // 目标对象(能够替换成任何的目标对象) Object targetObj = new UserService(); // AOP 代理 IUserService proxy = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), targetObj.getClass().getInterfaces(), new InvocationHandler() { // 方法匹配器 MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(* cn.bugstack.springframework.test.bean.IUserService.*(..))"); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (methodMatcher.matches(method, targetObj.getClass())) { // 方法拦截器 MethodInterceptor methodInterceptor = invocation -> { long start = System.currentTimeMillis(); try { return invocation.proceed(); } finally { System.out.println("监控 - Begin By AOP"); System.out.println("方法名称:" + invocation.getMethod().getName()); System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms"); System.out.println("监控 - End\r\n"); } }; // 反射调用 return methodInterceptor.invoke(new ReflectiveMethodInvocation(targetObj, method, args)); } return method.invoke(targetObj, args); } }); String result = proxy.queryUserInfo(); System.out.println("测试结果:" + result); }
测试结果
监控 - Begin By AOP 方法名称:queryUserInfo 方法耗时:86ms 监控 - End 测试结果:小傅哥,100001,深圳 Process finished with exit code 0
拆解案例
ReflectiveMethodInvocation
的使用,它目前已是实现 MethodInvocation
接口的一个包装后的类,参数信息包括:调用的对象、调用的方法、调用的入参。定义接口
cn.bugstack.springframework.aop.Pointcut
public interface Pointcut { /** * Return the ClassFilter for this pointcut. * @return the ClassFilter (never <code>null</code>) */ ClassFilter getClassFilter(); /** * Return the MethodMatcher for this pointcut. * @return the MethodMatcher (never <code>null</code>) */ MethodMatcher getMethodMatcher(); }
cn.bugstack.springframework.aop.ClassFilter
public interface ClassFilter { /** * Should the pointcut apply to the given interface or target class? * @param clazz the candidate target class * @return whether the advice should apply to the given target class */ boolean matches(Class<?> clazz); }
cn.bugstack.springframework.aop.MethodMatcher
public interface MethodMatcher { /** * Perform static checking whether the given method matches. If this * @return whether or not this method matches statically */ boolean matches(Method method, Class<?> targetClass); }
methodMatcher.matches(method, targetObj.getClass())
实现切点表达式类
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher { private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>(); static { SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION); } private final PointcutExpression pointcutExpression; public AspectJExpressionPointcut(String expression) { PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader()); pointcutExpression = pointcutParser.parsePointcutExpression(expression); } @Override public boolean matches(Class<?> clazz) { return pointcutExpression.couldMatchJoinPointsInType(clazz); } @Override public boolean matches(Method method, Class<?> targetClass) { return pointcutExpression.matchesMethodExecution(method).alwaysMatches(); } @Override public ClassFilter getClassFilter() { return this; } @Override public MethodMatcher getMethodMatcher() { return this; } }
pointcutExpression.couldMatchJoinPointsInType(clazz)
、pointcutExpression.matchesMethodExecution(method).alwaysMatches()
,这部份内容能够单独测试验证。匹配验证
@Test public void test_aop() throws NoSuchMethodException { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut("execution(* cn.bugstack.springframework.test.bean.UserService.*(..))"); Class<UserService> clazz = UserService.class; Method method = clazz.getDeclaredMethod("queryUserInfo"); System.out.println(pointcut.matches(clazz)); System.out.println(pointcut.matches(method, clazz)); // true、true }
cn.bugstack.springframework.aop.AdvisedSupport
public class AdvisedSupport { // 被代理的目标对象 private TargetSource targetSource; // 方法拦截器 private MethodInterceptor methodInterceptor; // 方法匹配器(检查目标方法是否符合通知条件) private MethodMatcher methodMatcher; // ...get/set }
定义接口
cn.bugstack.springframework.aop.framework
public interface AopProxy { Object getProxy(); }
cn.bugstack.springframework.aop.framework.JdkDynamicAopProxy
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler { private final AdvisedSupport advised; public JdkDynamicAopProxy(AdvisedSupport advised) { this.advised = advised; } @Override public Object getProxy() { return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getTargetSource().getTargetClass(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) { MethodInterceptor methodInterceptor = advised.getMethodInterceptor(); return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args)); } return method.invoke(advised.getTargetSource().getTarget(), args); } }
cn.bugstack.springframework.aop.framework.Cglib2AopProxy
public class Cglib2AopProxy implements AopProxy { private final AdvisedSupport advised; public Cglib2AopProxy(AdvisedSupport advised) { this.advised = advised; } @Override public Object getProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass()); enhancer.setInterfaces(advised.getTargetSource().getTargetClass()); enhancer.setCallback(new DynamicAdvisedInterceptor(advised)); return enhancer.create(); } private static class DynamicAdvisedInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy); if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) { return advised.getMethodInterceptor().invoke(methodInvocation); } return methodInvocation.proceed(); } } private static class CglibMethodInvocation extends ReflectiveMethodInvocation { @Override public Object proceed() throws Throwable { return this.methodProxy.invoke(this.target, this.arguments); } } }
public class UserService implements IUserService { public String queryUserInfo() { try { Thread.sleep(new Random(1).nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } return "小傅哥,100001,深圳"; } public String register(String userName) { try { Thread.sleep(new Random(1).nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } return "注册用户:" + userName + " success!"; } }
public class UserServiceInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { long start = System.currentTimeMillis(); try { return invocation.proceed(); } finally { System.out.println("监控 - Begin By AOP"); System.out.println("方法名称:" + invocation.getMethod()); System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms"); System.out.println("监控 - End\r\n"); } } }
@Test public void test_dynamic() { // 目标对象 IUserService userService = new UserService(); // 组装代理信息 AdvisedSupport advisedSupport = new AdvisedSupport(); advisedSupport.setTargetSource(new TargetSource(userService)); advisedSupport.setMethodInterceptor(new UserServiceInterceptor()); advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* cn.bugstack.springframework.test.bean.IUserService.*(..))")); // 代理对象(JdkDynamicAopProxy) IUserService proxy_jdk = (IUserService) new JdkDynamicAopProxy(advisedSupport).getProxy(); // 测试调用 System.out.println("测试结果:" + proxy_jdk.queryUserInfo()); // 代理对象(Cglib2AopProxy) IUserService proxy_cglib = (IUserService) new Cglib2AopProxy(advisedSupport).getProxy(); // 测试调用 System.out.println("测试结果:" + proxy_cglib.register("花花")); }
测试结果
监控 - Begin By AOP 方法名称:public abstract java.lang.String cn.bugstack.springframework.test.bean.IUserService.queryUserInfo() 方法耗时:86ms 监控 - End 测试结果:小傅哥,100001,深圳 监控 - Begin By AOP 方法名称:public java.lang.String cn.bugstack.springframework.test.bean.UserService.register(java.lang.String) 方法耗时:97ms 监控 - End 测试结果:注册用户:花花 success! Process finished with exit code 0