OOP(Object Oriented Programming,面向对象编程),通过封装、继承将程序抽象为各个层次的对象,进而组合为模块或者程序,达到了软件工程中的重用性、灵活性、扩展性。程序的运行笼统地可以看为各层次对象之间的相互调用。AOP(Aspect Oriented Programming,面向切面编程),将程序运行过程分解为一个个的切面,对特定的切面(某个步骤或者阶段)进行提取,达到解耦各种不同逻辑代码。OOP是在程序分块层面上进行考虑,而AOP则是在程序运行的切面上进行考虑。
可以将AOP理解为一种无损伤型的”切面”激光手术刀。OOP使属性和行为被封装为了一个严实、密不透风的对象。想要改变由对象保护着的方法,就可以通过该激光手术刀,既不损伤对象(即是,不破坏对象的封装),又不添加任何冗余的代码,实现对原对象的方法的增强处理。
不得不说,AOP实在是一种巧妙的编程思想!!!弥补了OOP中一些难以解决的问题。例如,1. 类应该是纯净的,不应含有与本身无关的逻辑。如日志跟踪的逻辑代码。这样的类就可以更好地重用,更有效地被AOP的切入更多的业务逻辑, 举例代码如下:
/* * 假如需要记录某只柯基狗的日常, * 我们总不能让它自己来记录吧?? * 如 下面的注释了的方法 * 看起来是不是非常怪异,一只狗狗自己给自己写日记 */class dog{void run(){/*note.write("散步了");*/ }void sleep(){/*note.write("又睡懒觉了");*/ }}2. OOP为不同类别的对象引入公共方法时,往往力不从心,造成大量的分散的重复代码,重用性真的很差,每次都要改动真的很麻烦。
class dog{private Note note = new Note();void run(){ note.write("散步了"); }void sleep(){ note.write("又睡懒觉了"); }}
本文中”特定处理”指的日志记录、事务管理、异常处理等等之类的各种通用的业务逻辑
主要分为两大类:一是采用动态代理,对被代理对象和特定处理进行修饰和封装,得到代理对象,从使得被代理对象中不需切入任何的代码,如图:简单的代理:实现不入侵原始对象而切入各种通用的业务逻辑(eg: 参数验证、日志记录方法等)
interface Interface{void doSomething();}/*原始对象*/class RealObject implements Interface{@Overridepublic void doSomething() { System.out.println("原始对象的行为"); }}/*代理*/class SimplProxy implements Interface {private Interface proxied;public SimplProxy(Interface proxied){this.proxied = proxied; }public void doSomething(){ System.out.println("处理一些通用的业务逻辑, 如参数校验等等"); proxied.doSomething(); }}/*调用者*/class Caller{public static void call(Interface iface){ iface.doSomething(); }public static void main(String[] args){ call(new SimplProxy(new RealObject())); }}/*输出:*/1.处理一些通用的业务逻辑, 如参数校验等等2.原始对象的行为就这样,一些通用的业务逻辑被代理简单地切入到了原始对象之前执行二是采用静态织入,如AspectJ,使用其特定的语法创建切面,在编译期间将切面织入代码中。又如,通过AspectJ编译出来的class文件与普通编译出来的有很大区别,这块没有了解,不再赘述。
权限控制、异常处理、缓存、事务管理、日志记录、数据校验等等
基于注解的零配置方式:一、启动@AspectJ注解支持,旭在相应的容器内,加入如下片段:
<beans xmlns:aop="http://www.springframework.org/schema/aop" <!-- 必须有相应的XML Schema 配置 --> http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd <!-- 必须相应的容器内,启动@AspectJ支持,如对Springmvc的Contrller织入, 则应在Springmvc.xml中配置 --><aop:aspectj-autoproxy /><!-- 扫描相应的包 -->二、定义切面bean
@Aspect@Compementpublic class Advice{/*定义切入点, 业务处理逻辑等等其他内容*/}三、定义@Before、@After、@Around等增强处理
/*定义切入点表达式*//*配置匹配service包下所有的类、所有的方法*/@Pointcut("execution(* com.xxx.xxx.service.*.*(..))")public void pointCutExpress(){ }四、定义处理方法
@After("pointCutExpress()")public void closeResource(){/*After注解,更适合于释放资源*/ }一、切入点注解
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyPointCut {/*模拟简单的注解定义切入点*/public String expression();}二、原始对象及接口
interface SomeMethods{void method1();void method2(String args);}public class Implementation implements SomeMethods{@Overridepublic void method1() { System.out.println("原始对象的方法1"); }@Overridepublic void method2(String args) { System.out.println("原始对象的方法2及参数:" + args); }}三、动态代理工厂
class MyAspect{@MyPointCut(expression = "com.auhnayuil.comm.Implementation.*")public void Logger(){ System.out.println(">>>>>>>>>>>>>>>>>正在记载日志中<<<<<<<<<<<<<<<<<<<<<<<"); }}class SimpleProxyFactory{/*简单代理工厂*/public static Object getProxyObject(final Object realObject, final Object aspectObject){/*代理对象 切面定义类*/final Class<?> realObjectClass = realObject.getClass();final Class<?> aspectObjectClass = aspectObject.getClass();return Proxy.newProxyInstance( realObjectClass.getClassLoader(), realObjectClass.getInterfaces(),new InvocationHandler(){/*模拟简单的@Before日志注解*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*加载切入点信息. 这里的方法Logger被硬编码了, 后期可以根据注解来解决*/ Method pointCutMethod = aspectObjectClass.getMethod("Logger", new Class[] {}); MyPointCut myPointCut = pointCutMethod.getAnnotation(MyPointCut.class);/*判断切入点, 并执行其方法*/ String expression = myPointCut.expression(); String[] express = expression.split("\\.");int exprLength = express.length;if("*".equals(express[exprLength - 1])){/*这里只演示一种情况*/ pointCutMethod.invoke(aspectObject, new Class[] {}); }/*执行原始对象的方法*/return method.invoke(realObject, args); } } ); }}public class ProxyDemo {public static void main(String[] args){ SomeMethods someMethods = new Implementation(); SomeMethods proxyObject = (SomeMethods) SimpleProxyFactory.getProxyObject(someMethods, new MyAspect()); proxyObject.method1(); proxyObject.method2("auhnayuiL"); }}四、输出结果
>>>>>>>>>>>>>>>>>正在记载日志中<<<<<<<<<<<<<<<<<<<<<<<原始对象的方法1>>>>>>>>>>>>>>>>>正在记载日志中<<<<<<<<<<<<<<<<<<<<<<<原始对象的方法2及参数:auhnayuiL转载于:https://www.cnblogs.com/Jason2018/p/8987777.html
