海安零距离 海安论坛 海安新闻 海安

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2834|回复: 0

Spring AOP 实现原理与 CGLIB 应用

[复制链接]

6234

主题

6234

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
18716
发表于 2019-12-27 19:16 | 显示全部楼层 |阅读模式
本博客强烈保举:
Java电子书高清PDF聚集免费下载
https://www.cnblogs.com/yuxiang1/p/12099324.html

AOP
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的增补和完满。
OOP引入封装、继承、多态等概念来创建一种对象条理结构,用于模仿公共行为的一个聚集。不外OOP答应开发者界说纵向的关系,但并不适合界说横向的关系,比方日志功能。
日志代码每每横向地散布在全部对象条理中,而与它对应的对象的焦点功能毫无关系对于其他范例的代码,如安全性、异常处置惩罚和透明的持续性也都是云云,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP计划中,它导致了大量代码的重复,而倒霉于各个模块的重用。

AOP技能恰恰相反,它使用一种称为"横切"的技能,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。
所谓"切面",简朴说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于淘汰体系的重复代码,低沉模块之间的耦合度,并有利于未来的可使用性和可维护性。

使用"横切"技能,AOP把软件体系分为两个部分:焦点关注点和横切关注点。业务处置惩罚的主要流程是焦点关注点,与之关系不大的部分是横切关注点。
横切关注点的一个特点是,他们常常发生在焦点关注点的多处,而各处根本相似,好比权限认证、日志、事物。AOP的作用在于分离体系中的各种关注点,将焦点关注点和横切关注点分脱离来。

AOP焦点概念
1、横切关注点
对哪些方法进行拦截,拦截后怎么处置惩罚,这些关注点称之为横切关注点
2、切面(aspect)
类是对物体特性的抽象,切面就是对横切关注点的抽象
3、毗连点(joinpoint)
被拦截到的点,由于Spring只支持方法范例的毗连点,所以在Spring中毗连点指的就是被拦截到的方法,现实上毗连点还可以是字段大概构造器
4、切入点(pointcut)
对毗连点进行拦截的界说
5、关照(advice)
所谓关照指的就是指拦截到毗连点之后要实验的代码,关照分为前置、后置、异常、终极、围绕关照五类
6、目的对象
代理的目的对象
7、织入(weave)
将切面应用到目的对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的条件下,引入可以在运行期为类动态地添加一些方法或字段

Spring对AOP的支持
Spring中AOP代理由Spring的IOC容器负责天生、管理,其依靠关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的别的bean实例作为目的,这种关系可由IOC容器的依靠注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,如许就可以为任何接口实例创建代理了
2、当必要代理的类不是代理接口的时间,Spring会切换为使用CGLIB代理,也可逼迫使用CGLIB
AOP编程着实是很简朴的事情,纵观AOP编程,步伐员只必要加入三个部分:
1、界说平凡业务组件
2、界说切入点,一个切入点大概横切多个业务组件
3、界说增强处置惩罚,增强处置惩罚就是在AOP框架为平凡业务组件织入的处置惩罚动作

所以进行AOP编程的关键就是界说切入点和界说增强处置惩罚,一旦界说了符合的切入点和增强处置惩罚,AOP框架将自动天生AOP代理,即:代理对象的方法=增强处置惩罚+被代理对象的方法。
下面给出一个Spring AOP的.xml文件模板,名字叫做aop.xml,之后的内容都在aop.xml上进行扩展:
  1.             
复制代码


基于Spring的AOP简朴实现
注意一下,在讲解之前,说明一点:使用Spring AOP,要乐成运行起代码,只用Spring提供给开发者的jar包是不敷的,请额外上网下载两个jar包:
1、aopalliance.jar
2、aspectjweaver.jar
开始讲解用Spring AOP的XML实现方式,先界说一个接口:
  1. public interface HelloWorld{    void printHelloWorld();    void doPrint();}
复制代码

界说两个接口实现类:
  1. public class HelloWorldImpl1 implements HelloWorld{    public void printHelloWorld()    {        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");    }        public void doPrint()    {        System.out.println("Enter HelloWorldImpl1.doPrint()");        return ;    }}
复制代码

  1. public class HelloWorldImpl2 implements HelloWorld{    public void printHelloWorld()    {        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");    }        public void doPrint()    {        System.out.println("Enter HelloWorldImpl2.doPrint()");        return ;    }}
复制代码


横切关注点,这里是打印时间:
  1. public class TimeHandler{    public void printTime()    {        System.out.println("CurrentTime = " + System.currentTimeMillis());    }}
复制代码


有这三个类就可以实现一个简朴的Spring AOP了,看一下aop.xml的设置:
  1.                                                                                                                                 
复制代码


写一个main函数调用一下:
  1. public static void main(String[] args){    ApplicationContext ctx =             new ClassPathXmlApplicationContext("aop.xml");            HelloWorld hw1 = (HelloWorld)ctx.getBean("helloWorldImpl1");    HelloWorld hw2 = (HelloWorld)ctx.getBean("helloWorldImpl2");    hw1.printHelloWorld();    System.out.println();    hw1.doPrint();        System.out.println();    hw2.printHelloWorld();    System.out.println();    hw2.doPrint();}
复制代码

运行结果为:
  1. CurrentTime = 1446129611993Enter HelloWorldImpl1.printHelloWorld()CurrentTime = 1446129611993CurrentTime = 1446129611994Enter HelloWorldImpl1.doPrint()CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.printHelloWorld()CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.doPrint()CurrentTime = 1446129611994
复制代码


看到给HelloWorld接口的两个实现类的全部方法都加上了代理,代理内容就是打印时间
基于Spring的AOP使用其他细节
1、增加一个横切关注点,打印日志,Java类为:
  1. public class LogHandler{    public void LogBefore()    {        System.out.println("Log before method");    }        public void LogAfter()    {        System.out.println("Log after method");    }}
复制代码

  1.                                                                                                                                                                                                                
复制代码


测试类稳定,打印结果为:
  1. CurrentTime = 1446130273734Log before methodEnter HelloWorldImpl1.printHelloWorld()Log after methodCurrentTime = 1446130273735CurrentTime = 1446130273736Log before methodEnter HelloWorldImpl1.doPrint()Log after methodCurrentTime = 1446130273736CurrentTime = 1446130273736Log before methodEnter HelloWorldImpl2.printHelloWorld()Log after methodCurrentTime = 1446130273736CurrentTime = 1446130273737Log before methodEnter HelloWorldImpl2.doPrint()Log after methodCurrentTime = 1446130273737
复制代码


要想让logHandler在timeHandler前使用有两个办法:
(1)aspect内里有一个order属性,order属性的数字就是横切关注点的次序
(2)把logHandler界说在timeHandler前面,Spring默认以aspect的界说次序作为织入次序
2、我只想织入接口中的某些方法
修改一下pointcut的expression就好了:
  1.                                                                                                                                                                                                                
复制代码


体现timeHandler只会织入HelloWorld接口print开头的方法,logHandler只会织入HelloWorld接口do开头的方法

3、逼迫使用CGLIB天生代理
前面说过Spring使用动态代理或是CGLIB天生代理是有规则的,高版本的Spring会自动选择是使用动态代理照旧CGLIB天生代理内容,当然我们也可以逼迫使用CGLIB天生代理,那就是内里有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于类的代理将起作用,如果proxy-target-class被设置为false大概这个属性被省略,那么基于接口的代理将起作用

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|深圳论坛-深圳人的网上家园  

GMT+8, 2020-6-3 11:41 , Processed in 0.150954 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表