【Spring之AOP】
2016-05-02 13:09
429 查看
什么是AOP?
-面向切面编程
-它是一种思想,可在不改变程序源码的情况下为程序添加额外的功能。
-允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。应用对象只实现业务逻辑即可,并不负责其他的系统级关注点。
-AOP专门用于处理系统中分布于各个模块中的交叉关注点的问题,在J2EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
AOP的发展过程?
-静态AOP:Aspect形式,通过特定的编译器,将实现后的Aspect编译并织入到系统的静态类中
-动态AOP:AOP的织入过程在系统运行开始之后进行,而不是预先编译到系统中
AOP术语?
-连接点:程序执行的某个特定位置,比如类初始化前、类初始化后、方法调用前、方法调用后等
-切点:通过切点来定位特定的连接点
-增强:织入到目标类连接点上的一段程序代码
-目标对象:增强逻辑的织入目标类
-引介:是一种特殊的增强,它为类添加一些属性和方法
-织入:为增强添加目标类的具体连接点上的过程
-代理:一个类被AOP织入增强后,会产生一个结果类,该类融合了原类和增强逻辑的代理类
-切面:由切点和增强组成,既包括了横切逻辑的定义,也包括了连接点的定义
AOP的原理剖析?
-AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理所包含的方法与目标对象的方法如下图所示:
使用AOP的步骤是:
定义普通业务组件 ---> 定义切入点 ---> 定义增强处理
代理对象的方法 = 增强处理 + 被代理对象的方法
AOP的通俗理解?
-一个组件A,不关心其他常用的服务组件B,但是这个组件A使用组件B的时候,不是组件A自身去调用,而是通过配置等其他方式,比如Spring中可以通过xml配置文件。这样就使得A压根就不需要知道服务组件B是怎样的,爱存在不存在,爱怎么存在都与A无关。A只关心自己的业务逻辑,具体A使用B的时候,配置文件去做,与具体的A组件无关。
AOP的实现方法?
(1)利用Proxy实现AOP功能 (JDK动态代理)
采用Proxy类方法,基本流程为:主函数--->代理--->目标对象的方法。对于Proxy类有一个使用前提,就是目标对象必须实现接口,否则不能使用这个方法。
实现AOP功能步骤如下:
创建接口:StudentInterface.java
创建接口实现类:StudentBean.java
创建代理工厂:ProxyFactory.java
总结:
目标对象必须实现接口
返回创建的代理对象
重写invoke()方法
限制条件放在invoke()方法中
(2)利用CGLIB实现AOP功能(CGLIB动态代理)
CGLIB(code generation library)是一个开源项目,它是一个强大的、高性能、高质量的code生成类库,它可以在运行期间扩展Java类和实现Java接口。
实现AOP功能步骤如下所示:
引入jar包
创建实体类
创建CGLIB代理类
创建入口类进行测试
(3)利用Spring XML文件配置方式实现AOP功能步骤如下:
引入jar包
配置AOP命名空间
创建目标对象类
创建切面
在配置文件中配置
创建入口类进行测试
-面向切面编程
-它是一种思想,可在不改变程序源码的情况下为程序添加额外的功能。
-允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。应用对象只实现业务逻辑即可,并不负责其他的系统级关注点。
-AOP专门用于处理系统中分布于各个模块中的交叉关注点的问题,在J2EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
AOP的发展过程?
-静态AOP:Aspect形式,通过特定的编译器,将实现后的Aspect编译并织入到系统的静态类中
-动态AOP:AOP的织入过程在系统运行开始之后进行,而不是预先编译到系统中
AOP术语?
-连接点:程序执行的某个特定位置,比如类初始化前、类初始化后、方法调用前、方法调用后等
-切点:通过切点来定位特定的连接点
-增强:织入到目标类连接点上的一段程序代码
-目标对象:增强逻辑的织入目标类
-引介:是一种特殊的增强,它为类添加一些属性和方法
-织入:为增强添加目标类的具体连接点上的过程
-代理:一个类被AOP织入增强后,会产生一个结果类,该类融合了原类和增强逻辑的代理类
-切面:由切点和增强组成,既包括了横切逻辑的定义,也包括了连接点的定义
AOP的原理剖析?
-AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理所包含的方法与目标对象的方法如下图所示:
使用AOP的步骤是:
定义普通业务组件 ---> 定义切入点 ---> 定义增强处理
代理对象的方法 = 增强处理 + 被代理对象的方法
AOP的通俗理解?
-一个组件A,不关心其他常用的服务组件B,但是这个组件A使用组件B的时候,不是组件A自身去调用,而是通过配置等其他方式,比如Spring中可以通过xml配置文件。这样就使得A压根就不需要知道服务组件B是怎样的,爱存在不存在,爱怎么存在都与A无关。A只关心自己的业务逻辑,具体A使用B的时候,配置文件去做,与具体的A组件无关。
AOP的实现方法?
(1)利用Proxy实现AOP功能 (JDK动态代理)
采用Proxy类方法,基本流程为:主函数--->代理--->目标对象的方法。对于Proxy类有一个使用前提,就是目标对象必须实现接口,否则不能使用这个方法。
实现AOP功能步骤如下:
创建接口:StudentInterface.java
创建接口实现类:StudentBean.java
创建代理工厂:ProxyFactory.java
public interface StudentInterface { public void print(); }
public class StudentBean implements StudentInterface { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public StudentBean() { } public StudentBean(String name) { super(); this.name = name; } @Override public void print() { System.out.println("hi student."); } }
public class ProxyFactory implements InvocationHandler { private Object object; public Object createStudentProxy(Object obj) { this.object = obj; //创建并返回代理 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { StudentBean studentBean = (StudentBean) object; Object obj = null; if(studentBean.getName() != null){ obj = method.invoke(object, args); }else{ System.out.println("学生姓名为空,代理类已经进行拦截."); } return obj; } }
public class Test001 { public static void main(String[] args) { StudentInterface s1 = new StudentBean(); ProxyFactory proxyFactory = new ProxyFactory(); StudentInterface s2 = (StudentInterface) proxyFactory .createStudentProxy(s1); s2.print(); } }
总结:
目标对象必须实现接口
返回创建的代理对象
重写invoke()方法
限制条件放在invoke()方法中
(2)利用CGLIB实现AOP功能(CGLIB动态代理)
CGLIB(code generation library)是一个开源项目,它是一个强大的、高性能、高质量的code生成类库,它可以在运行期间扩展Java类和实现Java接口。
实现AOP功能步骤如下所示:
引入jar包
创建实体类
创建CGLIB代理类
创建入口类进行测试
public class StudentBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public StudentBean() { } public StudentBean(String name) { super(); this.name = name; } public void print() { System.out.println("hi student."); } }
public class CGLIBProxyFactory implements MethodInterceptor{ private Object object; public Object createStudentProxy(Object obj){ this.object = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { StudentBean stu = (StudentBean) object; Object ret = null; if(stu.getName() != null){ methodProxy.invoke(object, args); }else{ System.out.println("学生姓名为空,方法已经被拦截."); } return ret; } }
public class Test002 { public static void main(String[] args) { StudentBean s1 = new StudentBean(); CGLIBProxyFactory cglibProxyFactory = new CGLIBProxyFactory(); StudentBean s2 = (StudentBean) cglibProxyFactory.createStudentProxy(s1); s2.print(); } }
(3)利用Spring XML文件配置方式实现AOP功能步骤如下:
引入jar包
配置AOP命名空间
创建目标对象类
创建切面
在配置文件中配置
创建入口类进行测试
public interface TrainStationAware { //售票方法 public String sellTicket(String name); //退票方法 public String returnTicket(String name); }
public class TrainStation implements TrainStationAware{ @Override public String sellTicket(String name) { System.out.println(name + "购票成功"); return "ok"; } @Override public String returnTicket(String name) { System.out.println(name + "退票成功"); return "ok2"; } }
public class XmlAdvice { /** * 在核心业务执行前执行,不能阻止核心业务的调用。 * * @param joinPoint */ private void doBefore(JoinPoint joinPoint) { System.out.println("-----doBefore().invoke-----"); } /** * 手动控制调用核心业务逻辑,以及调用前和调用后的处理, * * 注意:当核心业务抛异常后,立即退出,转向After Advice 执行完毕After Advice,再转到Throwing Advice * * @param pjp * @return * @throws Throwable */ private Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("-----doAround().invoke-----"); MethodSignature ms = (MethodSignature) pjp.getSignature(); Method method = ms.getMethod(); Object retVal = null; if("returnTicket".equals(method.getName())){ System.out.println("代理售票点不能办理退票"); }else{ retVal = pjp.proceed(); } System.out.println("-----End of doAround()------"); return retVal; } /** * 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice * * @param joinPoint */ private void doAfter(JoinPoint joinPoint) { System.out.println("-----doAfter().invoke-----"); } /** * 核心业务逻辑调用正常退出后,不管是否有返回值,正常退出后,均执行此Advice * * @param joinPoint */ private void doReturn(JoinPoint joinPoint) { System.out.println("-----doReturn().invoke-----"); } /** * 核心业务逻辑调用异常退出后,执行此Advice,处理错误信息 * * @param joinPoint * @param ex */ private void doThrowing(JoinPoint joinPoint, Throwable ex) { System.out.println("-----doThrowing().invoke-----"); System.out.println(" 错误信息:" + ex.getMessage()); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean id="trainStationAware" class="com.bear.spring.aop.TrainStation"/> <bean id="xmlHandler" class="com.bear.spring.aop.XmlAdvice" /> <aop:config> <aop:aspect id="aspect" ref="xmlHandler"> <aop:pointcut id="pointUserMgr" expression="execution(* com.bear.spring.aop.*.*Ticket(..))"/> <aop:before method="doBefore" pointcut-ref="pointUserMgr"/> <aop:after method="doAfter" pointcut-ref="pointUserMgr"/> <aop:around method="doAround" pointcut-ref="pointUserMgr"/> <aop:after-returning method="doReturn" pointcut-ref="pointUserMgr"/> <aop:after-throwing method="doThrowing" throwing="ex" pointcut-ref="pointUserMgr"/> </aop:aspect> </aop:config> </beans>
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); TrainStationAware tsa = (TrainStationAware) context.getBean("trainStationAware"); tsa.sellTicket("张三"); // tsa.returnTicket("李四"); }
相关文章推荐
- 码农小汪-Spring MVC注解式控制器简介
- Enumeration接口和Iterator接口的区别
- POJ3259-JAVA语言描述-Bellman_Ford算法
- Spring.Net初认识——竹子整理
- Java中获取文件大小的正确方法
- java基础一(阅读Head First Java记录)
- JAVA 解析JSON数据
- junit4 javaee 5.0 jpa SSH 单元测试问题集锦
- java关于参数传递的思考
- java学习--冒泡排序
- Spark-Avro学习7之Java Avro使用(生成code方式)
- 码农小汪-Spring MVC 处理器拦截器详解
- Java错误提示:Syntax error, insert "}" to complete Block
- RxJava与Retrofit结合学习
- SpringData 学习(3)—— 通过“规范”的方法实现查询
- Ubuntu Android 开发(一) JDK 安装
- Java File类的使用
- MyEclipse配置SVN
- 【Java学习-J.160430.0.15】笔记8-使用JDBC连接数据库
- Java 正则表达式