Spring之AOP一
面向切片式编程不仅在Java中存在,在其他语言也是存在,例如asp.net的管道模型中,可以利用aop来进行自定义一些操作,比如权限认证、日志等。今天主要是引入AOP,具体它涉及到的专有名词先不做解释。
一、横切纵切
首先要知道什么是横切什么是纵切(吐槽大会的观众们这也是知识点),下面的两张图是从网上找的,是讨论刨妇产是横切好还是纵切好的问题,知道什么是横切什么是纵切之后,我们也可以用莲藕来做比喻,横切切出来是圆的,纵切就不是了。


二、AOP
对于一些系统特别时生产环境的问题有些是在UAT或者ST环境是发现不了的,但又不可能用真时的正式环境来进行测试,我们做项目一般都会增加日志输出,这样未来可以通过日志来定位发现问题,那就需要在每个方法中增加日志信息,并需要进行捕获异常,如果按照一般的做法那就需要在每个方法中增加日志信息,并在方法中增加try catch来进行捕获日常,这样就会很麻烦,哪天我又不想增加日志信息、捕获异常了那还需要修改代码,而且影响的范围也是特别的大,这样就体现不了低耦合的特点。那该如何是好呢?于是乎AOP来了。AOP技术利用一种称为“横切”的技术,解剖封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,这样就能减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。红字部分基本把AOP的作用解释清楚了,它会将多个类的公共行为封装到一个可重用模块,然后将这个模糊注入里面,这里有个切的过程,不是内部操作,内部操作那还是复用了,是外部来进行操作。
三、代码中实现AOP
还是在上面博客代码的基础上,新建了一个ServiceImplA类,它实现了IService接口,我想实现这样一个功能,就是想在调用service方法前后增加日志打印或为service方法增加try catch,那该怎么做呢?
package Cuiyw.Spring.IService;
public interface IService {
public void service(String name) throws Exception;
}
package Cuiyw.Spring.Service;
import Cuiyw.Spring.IService.IService;
public class ServiceImplA implements IService{
public void service(String name) {
// TODO Auto-generated method stub
System.out.println("ServiceImplA name"+name);
}
}
1.在每处调用的地方增加日志和try catch
这种也是一种方法,但缺点是很明显的,就是每处都要更改,量也会很大,显然不可取。这里是每个点都要加,一个方法可能被调用多处,那就要写多次。
2.代理模式
代理模式又分为动态代理模式和静态代理模式。
(1)静态代理
静态代理关键是在代理对象和目标对象实现共同的接口,并且代理对象持有目标对象的引用。这里我创建了类ProxyServiceA,它实现IService接口,同时将实现IService接口的对象作为一个属性。
package Cuiyw.Spring.Service;
import Cuiyw.Spring.IService.IService;
public class ProxyServiceA implements IService{
public ProxyServiceA(IService service) {
super();
this.service = service;
}
private IService service;
public void service(String name) throws Exception {
// TODO Auto-generated method stub
System.out.println("log start");
try{
service.service(name);
}
catch(Exception e)
{
throw e;
}
System.out.println("log end");
}
}
上面的代码确实能为实现IService接口的对象增加调用前后的方法,并且增加了try catch。但是问题又来了。项目中接口可不止一个,可能会有很多,而且每个接口中的方法也会有好多,如果这样一个一个的增加不也是个问题。to be or not to be,that is a question.虽然比第一种方式,这种只需在每个方法中设置一次。
(2)动态代理
静态代理虽然也能解决上面增加日志和try catch来捕获异常,但是还是很麻烦,每个方法都要设置,于是动态代理来解决这个问题了。动态代理实现主要是实现InvocationHandler,并且将目标对象注入到代理对象中,利用反射机制来执行目标对象的方法。
package Cuiyw.Spring.Service; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class DynaProxyServiceA implements InvocationHandler { private Object target;//目标对象
public Object bind(Object object){
this.target = object;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null; System.out.println("log start");
try{
result = method.invoke(this.target, args);
}
catch(Exception e)
{
throw e;
}
System.out.println("log end");
return result;
} }
IService service = (IService) new DynaProxyServiceA().bind(new ServiceImplA());
service.service("cuiyw");

(3)2的升华
上面通过动态代理可以实现在方法前后打印日志以及捕获异常,但是打印日志也可能有几种日志啊,现在是之间输出到操作台,那可能会是输入到文件或数据库,那肿么办呢?这里打印日志的操作我们也可以进一步的抽象,还是先创建一个接口ILog,然后创建一个类ConsoleLog实现ILog这个接口。
package Cuiyw.Spring.Service;
import java.lang.reflect.Method;
public interface ILog {
public void start(Method method) throws Exception;
public void end(Method method) throws Exception;
}
package Cuiyw.Spring.Service; import java.lang.reflect.Method;
import java.util.Date; public class ConsoleLog implements ILog{ public void start(Method method) throws Exception {
// TODO Auto-generated method stub
System.out.println(new Date()+" method name:"+method.getName() + " start..."); } public void end(Method method) throws Exception {
// TODO Auto-generated method stub
System.out.println(new Date()+" method name:"+ method.getName() + " end...");
} }
然后将打印对象也在动态代理中抽象。
package Cuiyw.Spring.Service; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class DynaProxyServiceA implements InvocationHandler { //调用对象
private Object proxy;
//目标对象
private Object target; public Object bind(Object object,Object proxy){
this.target = object;
this.proxy=proxy;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null; //反射得到操作者的实例
Class<? extends Object> clazz = this.proxy.getClass();
//反射得到操作者的Start方法
Method start =clazz.getDeclaredMethod("start",new Class[]{Method.class});
//反射执行start方法
start.invoke(this.proxy, new Object[]{method});
//执行要处理对象的原本方法
result=method.invoke(this.target, args);
//反射得到操作者的end方法
Method end = clazz.getDeclaredMethod("end", new Class[]{Method.class});
//反射执行end方法
end.invoke(this.proxy, new Object[]{method});
return result;
} }
IService service = (IService) new DynaProxyServiceA().bind(new ServiceImplA(),new ConsoleLog());
service.service("cuiyw");

上面是把start、end都在动态代理中执行了,其实我们可以判断哪个方法有被实现,然后再进行执行。
四、总结感悟
上面标题是代码中实现AOP,虽并未提到AOP但是,如果把上面的能理解明白了,那AOP就很好理解了,也不用理解什么切点、连接点等这些名字就能用。
最后聊几句大家可能都会遇到的问题,上周项目组开会说项目组有重组的可能,哎,感觉公司还真是够冷漠无情的,有利用价值就利用,没利用价值就被干掉,不管年龄大小,自身本来就没安全感,遇到这事还真是觉得对未来更加恐惧,害怕以后也会遇到这样的情况,这也让我更加下定决心要尽快把java学好。留给中国队的时间不多了。
Spring之AOP一的更多相关文章
- Spring基于AOP的事务管理
Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...
- Spring实现AOP的4种方式
了解AOP的相关术语:1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完成的工作和何时需要执行这个工作.2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“ ...
- spring的AOP
最近公司项目中需要添加一个日志记录功能,就是可以清楚的看到谁在什么时间做了什么事情,因为项目已经运行很长时间,这个最初没有开来进来,所以就用spring的面向切面编程来实现这个功能.在做的时候对spr ...
- Spring(五)AOP简述
一.AOP简述 AOP全称是:aspect-oriented programming,它是面向切面编号的思想核心, AOP和OOP既面向对象的编程语言,不相冲突,它们是两个相辅相成的设计模式型 AOP ...
- Spring中AOP原理,源码学习笔记
一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...
- Spring之AOP面向切片
一.理论基础: AOP(Aspectoriented programming)面向切片/服务的编程,在Spring中使用最多的是对事物的处理.而AOP这种思想在程序中很多地方可以使用的,比如说, ...
- 利用CGLib实现动态代理实现Spring的AOP
当我们用Proxy 实现Spring的AOP的时候, 我们的代理类必须实现了委托类的接口才能实现. 而如果代理类没有实现委托类的接口怎么办? 那么我们就可以通过CGLib来实现 package cn. ...
- spring之aop概念和配置
面向切面的一些概念: 简单说: 连接点就一些方法,在这些方法基础上需要额外的一些业务需求处理. 切入点就是方法所代表的功能点组合起来的功能需求. 通知就是那些额外的操作. 织入就是使用代理实现整个切入 ...
- Spring的AOP与代理
spring 支持两种注入方式: setter/constructor 支持多种配置方式: xml/java5注解/java类配置 支持两种事务管理: 声明性/编程性 实际上上述方式只有一个就能保证系 ...
- Spring 实践 -AOP
Spring 实践 标签: Java与设计模式 AOP引介 AOP(Aspect Oriented Programing)面向切面编程采用横向抽取机制,以取代传统的纵向继承体系的重复性代码(如性能监控 ...
随机推荐
- 转 html5离线储存,application cache,manifest使用体验
html5离线应用application cache 最近在APP里新增一个论坛模块,为了快速地完成,决定将整个论坛模块做成WEB APP,WEB APP最致命的就是用户体验问题,页面跳转和过多的请求 ...
- 如何运用GitHub来提高生产效率
这是一篇GitHub的入门级文章,主要针对git的初学者.我们将讨论初学者最关心的一些问题,如:为什么我们要使用GitHub,它的应用有哪些,如何运用它去帮助我们提高工作效率,以及它的基本用法有哪些. ...
- 微信公众平台快速开发框架 For Core 2.0 beta –JCSoft.WX.Core 5.2.0 beta发布
写在前面 最近比较忙,都没有好好维护博客,今天拿个半成品来交代吧. 记不清上次关于微信公众号快速开发框架(简称JCWX)的更新是什么时候了,自从更新到支持.Net Framework 4.0以后基本上 ...
- 使用CXF 2.7.5出现的java.lang.RuntimeException: Cannot create a secure XMLInputFactory错误解决
昨天启动工程测试webservice服务,结果发现服务一调用就报java.lang.RuntimeException: Cannot create a secure XMLInputFactory j ...
- Photoshop颜色出现比较大的偏差,偏色严重,显示器配置文件2351似乎有问题
其实出现这个问题是因为 显示器的配置问题.并不是PS版本或者电脑系统问题. 一般在你首次启动PS的时候会出现提示:显示器配置文件2351似乎有问题. 如果你点击了继续运行那以后你使用PS打开任何文件都 ...
- dubbo专题」dubbo其实很简单,就是一个远程服务调用的框架(1)
一.dubbo是什么? 1)本质:一个Jar包,一个分布式框架,,一个远程服务调用的分布式框架. 既然是新手教学,肯定很多同学不明白什么是分布式和远程服务调用,为什么要分布式,为什么要远程调用.我简单 ...
- 用C#生成不重复的随机数
我们在做能自动生成试卷的考试系统时,常常需要随机生成一组不重复的题目,在.net Framework中提供了一个专门用来产生随机数的类System.Random. 对于随机数,大家都知道,计算机不 可 ...
- [转载] Java线程池框架源码分析
转载自http://www.linuxidc.com/Linux/2014-11/108791.htm 相关类Executor,Executors,AbstractExecutorService,Ex ...
- python进阶---Python中的socket编程
初识socket编程 一.前言 socket基于C\S架构(客户端\服务端)的编程模型,在Python中是以socket模块存在的. Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是 ...
- 【Win 10 应用开发】UI Composition 札记(七):基于表达式的动画
上一篇烂文中,老周给大伙伴们介绍过了几个比较好玩的动画.本篇咱们深化主题,说一说基于表达式的动画.这名字好理解,就是你可以用公式 / 等式来产生动画的目标值.比如,你想让某个可视化对象的高度减半,你的 ...