时间:2021-05-20
一、AOP 的基本概念
1.1 什么是 AOP
Aspect Oriented Programming,面向切面编程。
就跟我们说 OOP 是面向对象一样,AOP 是面向切面的。切面是分散在应用中的一个标准代码或功能。切面通常与实际的业务逻辑不同(例如,事务管理)。每个切面专注于一个特定的环切功能。
这里的切面呢,可以理解为横切。比如在所有的 DAO 层方法上加上一个同样的切面,功能是记录日志;又或者在某个接口上应用一个切面,作用是检查权限。
AOP 是基于代理来实现的。而代理又分为静态代理和动态代理。两者的区别在于代理类于何时生成。
下面我们讲讲代理是怎么回事?
1.2 代理与 Spring AOP
代理分为静态代理和动态代理:
Spring AOP 原理:
Spring AOP 中默认使用 JDK 动态代理,通过反射获取被代理的类,这个类必须实现一个接口。如果目标类没有实现接口,就会默认使用 CGLIB Proxy 来动态生成代理目标类,后者是被代理类的子类。
可以通过获取代理对象并打印的方式来查看其类型(JDK Proxy 下是 com.sun.prxy, CGlib 下是子类.
AspectJ: 用特定的编译器和语法,在编译时增强,实现了静态代理技术。
1.3 Spring AOP 与 AspectJ 的区别
AspectJ 是一套完整的 AOP 解决方案,而 Spring AOP 并不是 —— 它只是在 Spring 框架下满足其使用要求的一个解决方法,比如 Spring AOP 仅支持对方法使用切面。
二、静态代理
2.1 AspectJ 静态代理
基于特殊的编译器和语法。这里不多介绍了。
IDEA 下编译 AspectJ 可以参考这篇:https://blog.csdn.net/gavin_john/article/details/80156963
2.2 JDK 静态代理
实际上是利用实现一个具体的代理类来调用业务类。代理类持有了一个业务类的引用。
更概况地说,JDK 静态代理体现的是一种设计模式。
缺点很明显,代码冗余,难以维护。
这里以借书和还书这两个行为来作为一个示例:
编写一个 BookService 接口:
publicinterfaceBookService{booleanborrow(Stringid,StringuserName);booleanreBack(Stringid,StringuserName);}然后实现这个接口:
publicclassBookServiceImplimplementsBookService{@Overridepublicbooleanborrow(Stringid,StringuserName){System.out.println(userName+"借书:"+id);returntrue;}@OverridepublicbooleanreBack(Stringid,StringuserName){System.out.println(userName+"还书:"+id);returntrue;}}下面我们来编写BookService的代理类:
publicclassBookProxyimplementsBookService{privateBookServiceImplbookService;publicBookProxy(BookServiceImplbookService){this.bookService=bookService;}@Overridepublicbooleanborrow(Stringid,StringuserName){booleanres=false;if(check()){res=bookService.borrow(id,userName);}addLog();returnres;}@OverridepublicbooleanreBack(Stringid,StringuserName){booleanres=false;if(check()){res=bookService.reBack(id,userName);}addLog();returnres;}//privatebooleancheck(){System.out.println("检查权限");returntrue;}privatevoidaddLog(){System.out.println("操作完成");}}编写一个测试类:
publicclassMainTest{publicstaticvoidmain(String[]args){BookProxyproxy=newBookProxy(newBookServiceImpl());proxy.borrow("123","eknown");proxy.reBack("234","java");}}这里我们可以看到,JDK 静态代理就是说在原来的实现类上套一层代理。它好像是体现了代理模式,但实际上并没有带来太多的好处。代码相当冗余,也不利于维护。
真正体现代理模式好处的还是动态代理,下面我们来看看动态代理的原理。
三、动态代理
动态代理是程序运行时,由 JVM 根据反射等机制动态生成代理类的。
也就是说,程序运行前,我们仅仅定义了代理的规则,而不知道代理类具体长什么样,这不像上面的静态代理里,我们完整地定义了代理对象。
3.1 JDK 动态代理
JDK 动态代理是基于接口的。
我们可以通过实现InvocationHandler接口来手动创建一个 JDK 代理类。
首先需要定义一个接口,让业务类和代理类都实现这个接口。
然后编写一个 InvocationHandler 接口的实现类:
publicclassBookProxyimplementsInvocationHandler{//被该代理类处理的业务类privateBookServicebookService;publicBookProxy(BookServicebookService){this.bookService=bookService;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectres=null;if(check()){//调用实际的method,参数是接口+参数res=method.invoke(bookService,args);}addLog();returnres;}privatebooleancheck(){System.out.println("检查权限");returntrue;}privatevoidaddLog(){System.out.println("操作完成");}}测试:
publicclassMainTest{publicstaticvoidmain(String[]args){//创建被代理的实际业务类BookServiceImplbookServiceImpl=newBookServiceImpl();ClassLoaderclassLoader=bookServiceImpl.getClass().getClassLoader();//获取所有的接口方法Class[]interfaces=bookServiceImpl.getClass().getInterfaces();//构造HandlerInvocationHandlerinvocationHandler=newBookProxy(bookServiceImpl);//创建代理Objectobj=Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);BookServicebookService=(BookService)obj;bookService.borrow("abc","eknown");bookService.reBack("c23","py");}}3.2 CGLIB 动态代理
CGLIB 代理的原理是:让代理类继承业务类(也就自动拥有了业务类的所有非 final 的 public 方法)
我们这里手动编写一个 CGLIB 的代理试试看。
首先我们有一个 BookServiceImpl 业务类,这个业务类可以实现接口,也可以就是单纯的一个业务类。
然后我们定义一个 BookCglibProxy 类:
publicclassBookCglibProxyimplementsMethodInterceptor{@OverridepublicObjectintercept(Objecto,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{check();//调用实际的methodObjectobj=methodProxy.invokeSuper(o,objects);addLog();returnobj;}privatebooleancheck(){System.out.println("检查权限");returntrue;}privatevoidaddLog(){System.out.println("操作完成");}}测试类:
publicclassCglibTest{publicstaticvoidmain(String[]args){BookServiceImplbookServiceImpl=newBookServiceImpl();BookCglibProxyproxy=newBookCglibProxy();//cjlib中的增强器,用于创建动态代理(被代理类的子类)Enhancerenhancer=newEnhancer();//设置要被代理的类enhancer.setSuperclass(bookServiceImpl.getClass());//设置回调enhancer.setCallback(proxy);//强转成父类BookServiceImplproxyResult=(BookServiceImpl)enhancer.create();proxyResult.borrow("12333","ye");proxyResult.reBack("123","fe");}}在第一节我们提到过 Spring AOP 是基于 JDK 动态代理和 CGLIB 动态代理的。下面我们来 Spring AOP 的一些基本案例。
四、Spring AOP 实例
AOP 中一些概念词汇,通过这些词汇,我们可以对 AOP 有更高一层的抽象。
Spring AOP 有两种实现方式:基于 XML 或基于注解。更流行、更方便的是后者。(阿 sir,不会还有人用 XML 来做 Bean 的配置文件吧?)
4.1 基于 XML 的实例
首先定义一下接口和实现类(没有注解的!)。再编写一个代理类:
这里的代理类方法以 JoinPoint 为参数即可:
publicclassBookAspect{publicvoidcheckUser(JoinPointpoint){System.out.println("-----before-----");Object[]args=point.getArgs();for(Objectarg:args){System.out.println(arg);}System.out.println("检查用户权限...");}publicvoidsaveLog(JoinPointpoint){System.out.println("-----after-----");Object[]args=point.getArgs();for(Objectarg:args){System.out.println(arg);}System.out.println("请求完毕,记录日志...");}}然后编写 Spring 的配置文件:
<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://.example.springaopdemo.boot.UserMonitor)")publicObjectuserRolePointCut(ProceedingJoinPointpoint){System.out.println("检查用户权限...");//获取参数Object[]args=point.getArgs();Class<?>[]argTypes=newClass[point.getArgs().length];for(inti=0;i<args.length;i++){argTypes[i]=args[i].getClass();}//获取方法Methodmethod=null;try{method=point.getTarget().getClass().getMethod(point.getSignature().getName(),argTypes);}catch(NoSuchMethodException|SecurityExceptione){e.printStackTrace();}//获取方法上的该注解,之后可以根据注解中的值进行一些操作,比如判定是否具有权限UserMonitormonitor=method.getAnnotation(UserMonitor.class);System.out.println(monitor);Objectobj=null;try{obj=point.proceed();}catch(Throwablethrowable){throwable.printStackTrace();}returnobj;}以上就是Spring AOP 与代理的概念与使用的详细内容,更多关于Spring AOP 与代理的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
Java反射机制与动态代理,使得Java更加强大,Spring核心概念IoC、AOP就是通过反射机制与动态代理实现的。1Java反射示例:Useruser=ne
Spring是一个十分火热开源框架,而AOP(面向切面编程)则是Spring最重要的概念之一,为了更好的理解和学习AOP的思想,使用核心库来实现一次不失为一
Spring框架。和Struts框架一样,Spring其实也是开源框架,它是RodJohnson创造出来的,由AOP与IOC两个部分组成。AOP指的是面向方面编
@Transactional内部调用例子🌰在Spring的AOP代理下,只有目标方法由外部调用,目标方法才由Spring生成的代理对象来管理,这
spring对AOP的实现提供了很好的支持。下面我们就使用Spring的注解来完成AOP做一个例子。首先,为了使用Spring的AOP注解功能,必须导入如下几个