Spring基础知识(5)-AOP
2016-05-12 11:02
585 查看
一、什么是 AOP
AOP Aspect Oriented Programing 面向切面编程 , 人们说AOP 是对 OOP (面向对象编程)思想一个延伸。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(主流的AOP的应用方向:性能监视、事务管理、安全检查、缓存)
如果把共用的方法写在类里边,就无法复用,而用继承可以解决这个问题,如果不用继承采用AOP(其实AOP横向抽取机制就是代理机制),也就是说如果想让很多DAO都 实现这个共用的方法,可以为具体的类创建一个代理类,
如果有了代理类,我们访问该类的任何方法,都会经过代理类
在传统的代码结构中:我们会通过类的继承来完成一些代码的复用,这是一种纵向结构代码复用。
☆☆☆:AOP 面向切面编程 底层原理 代理!!!
相关术语:
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
Target(目标对象):代理的目标对象
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面): 是切入点和通知(引介)的结合
二、 AOP 的底层实现
AOP 底层使用的代理技术 : JDK动态代理 和 CGlib的动态代理
1、 JDK动态代理
原理: 针对内存中Class对象,使用类加载器 动态为目标对象的实现接口创建代理类
* 代理类 是动态创建的, 代理类 和 被代理对象 实现相同接口
* 被代理对象 必须要实现 接口 (JDK代理 只能针对接口 进行代理 )
使用JDK动态代理:
2、 使用CGlib 完成动态代理
* JDK 动态代理原理, 为目标对象 接口生成代理对象 ,对于不使用接口的业务类,无法使用JDK动态代理
CGLIB(Code Generation Library)是一个开源项目!
是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate支持CGlib 来实现PO字节码的动态生成。
* Hibernate 默认PO 字节码生成技术 javassist
CGLIB 是一个第三方技术,使用时 ,需要下载 jar 包
http://sourceforge.net/projects/cglib/
* Spring3.2 版本, spring-core jar包 已经集成 cglib 开发类
☆原理 : CGlib采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题
使用CGLIB动态代理:
使用代理效果:
结论:
1).若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
2).若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类程序中应优先对接口创建代理,便于程序解耦维护
AOP Aspect Oriented Programing 面向切面编程 , 人们说AOP 是对 OOP (面向对象编程)思想一个延伸。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(主流的AOP的应用方向:性能监视、事务管理、安全检查、缓存)
如果把共用的方法写在类里边,就无法复用,而用继承可以解决这个问题,如果不用继承采用AOP(其实AOP横向抽取机制就是代理机制),也就是说如果想让很多DAO都 实现这个共用的方法,可以为具体的类创建一个代理类,
如果有了代理类,我们访问该类的任何方法,都会经过代理类
在传统的代码结构中:我们会通过类的继承来完成一些代码的复用,这是一种纵向结构代码复用。
☆☆☆:AOP 面向切面编程 底层原理 代理!!!
相关术语:
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
Target(目标对象):代理的目标对象
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面): 是切入点和通知(引介)的结合
二、 AOP 的底层实现
AOP 底层使用的代理技术 : JDK动态代理 和 CGlib的动态代理
1、 JDK动态代理
原理: 针对内存中Class对象,使用类加载器 动态为目标对象的实现接口创建代理类
* 代理类 是动态创建的, 代理类 和 被代理对象 实现相同接口
* 被代理对象 必须要实现 接口 (JDK代理 只能针对接口 进行代理 )
package lsq.spring.aop.jdkproxy; /** * 用户数据库操作 * * @author lishanquan * */ public interface UserDao { public void add(); public void search(); }
package lsq.spring.aop.jdkproxy; public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("添加用户……"); } @Override public void search() { System.out.println("查询用户……"); } }
package lsq.spring.aop.jdkproxy; import org.junit.Test; public class JDKProxyTest { @Test //代理前操作 public void demo1(){ //没有代理 UserDao userDao = new UserDaoImpl(); userDao.add(); userDao.search(); }效果:
使用JDK动态代理:
package lsq.spring.aop.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK代理 * * @author lishanquan * */ public class MyJDKProxy implements InvocationHandler{ //把代理对象作为成员变量 private UserDao userDao; //通过被代理对象构造代理对象 public MyJDKProxy(UserDao userDao){ this.userDao = userDao; } /** * 使用JDK进行动态代理 * @return */ public UserDao createJDKProxy(){ return (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this); } @Override //访问被代理对象的任何方法,都会执行invoke public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //针对add方法进行增强,记录日志…… if(method.getName().equals("add")){ //如果访问的是add方法 System.out.println("记录日志……"); return method.invoke(userDao, args); }else{ //其它方法 return method.invoke(userDao, args); } } }
package lsq.spring.aop.jdkproxy; import org.junit.Test; public class JDKProxyTest { @Test //测试JDK动态代理 public void demo2(){ //创建被代理对象 UserDao userDao = new UserDaoImpl(); //根据被代理对象创建代理对象 MyJDKProxy jdkProxy = new MyJDKProxy(userDao); UserDao proxy = jdkProxy.createJDKProxy(); //执行代理对象方法 proxy.add(); proxy.search(); } }使用JDK动态代理的效果:
2、 使用CGlib 完成动态代理
* JDK 动态代理原理, 为目标对象 接口生成代理对象 ,对于不使用接口的业务类,无法使用JDK动态代理
CGLIB(Code Generation Library)是一个开源项目!
是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate支持CGlib 来实现PO字节码的动态生成。
* Hibernate 默认PO 字节码生成技术 javassist
CGLIB 是一个第三方技术,使用时 ,需要下载 jar 包
http://sourceforge.net/projects/cglib/
* Spring3.2 版本, spring-core jar包 已经集成 cglib 开发类
☆原理 : CGlib采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题
package lsq.spring.aop.cglibproxy; /** * 商品操作类(被代理对象) * * @author lishanquan * */ public class ProductDao { public void addProduct(){ System.out.println("添加商品……"); } public void deleteProduct(){ System.out.println("删除商品……"); } }
package lsq.spring.aop.cglibproxy; import org.junit.Test; public class CGLibProxyTest { @Test //未使用代理 public void demo1(){ ProductDao productDao = new ProductDao(); productDao.addProduct(); productDao.deleteProduct(); } }未使用代理效果:
使用CGLIB动态代理:
package lsq.spring.aop.cglibproxy; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; /** * CGLIB代理 * * @author lishanquan * */ public class MyCGLIBProxy implements MethodInterceptor { //目标对象 private ProductDao productDao; //通过构造器传入被代理对象 public MyCGLIBProxy(ProductDao productDao){ this.productDao = productDao; } //创建代理 public ProductDao createCglibProxy(){ //创建代理的核心对象 Enhancer enhancer = new Enhancer(); //设置被代理对象(为类创建子类) enhancer.setSuperclass(productDao.getClass()); //设置回调函数 enhancer.setCallback(this); //返回代理(返回代理子类对象) return (ProductDao) enhancer.create(); } @Override // 被代理对象所有方法执行 ,都会调用 intercept 方法 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 为 addProduct 计算运行时间 if(method.getName().equals("addProduct")){ //当前执行方法 long start = System.currentTimeMillis(); Object result = methodProxy.invokeSuper(proxy, args); long end = System.currentTimeMillis(); System.out.println("addProduct方法运行时间 : " + (end - start)); return result; }else{ // 不进行增强 return methodProxy.invokeSuper(proxy, args); } } }
package lsq.spring.aop.cglibproxy; import org.junit.Test; public class CGLibProxyTest { @Test //使用CGLIB代理 public void demo2(){ //创建被代理对象 ProductDao productDao = new ProductDao(); //创建代理 MyCGLIBProxy cglibProxy = new MyCGLIBProxy(productDao); ProductDao proxy = cglibProxy.createCglibProxy(); //执行代理对象方法 proxy.addProduct(); proxy.deleteProduct(); } }
使用代理效果:
结论:
1).若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
2).若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类程序中应优先对接口创建代理,便于程序解耦维护
相关文章推荐
- eclipse中导入一个android工程和Web工程有The import android cannot be resolved错误怎么办
- java生成视频的缩略图
- java日期时间的运算
- Java中的构造函数
- SSM学习之路--JAVA环境搭建
- Java反射机制知识点
- Spring+SpringMVC+MyBatis+Maven框架整合
- Spring+SpringMVC+MyBatis+Maven框架整合
- Javaweb学习之中文乱码问题
- Spring 简述
- 利用spring 实现文件上传、下载
- struts2标签详解
- java多线程
- Java文件输出流
- Ubuntu 16.04 x64安装低版本软件(如openjdk-7/libgif4)的办法
- Dubbo源码分析之二:spring集成之注解
- Java中关于Null的9个解释(Java Null详解)
- Java之Clone()
- 找到最耗CPU的java线程
- JAVA并发实现五(生产者和消费者模式Condition方式实现)