AOP思考

来源:互联网 发布:淘宝小卖家怎么定位 编辑:程序博客网 时间:2024/06/05 04:57
最近在帮一个同事解决AOP异常时,对自己的AOP理解做了一个提纲总结,便于以后回忆。

1. AOP理解

     1)AOP是什么

          AOP,面向切面编程思想。该思想提倡将各组件间具有横切性质的公共逻辑用“切面”封装起来,通过代理以“切入”的方式调用,实现代码的分层、解耦。

     2)AOP解决什么问题
     
          AOP解决的问题是代码逻辑的解耦和分层、公共逻辑的封装和调用问题。

     3)AOP如何解决问题

          首先,按照OOP思想将公共逻辑用对象(切面)封装起来;
          然后,构建业务组件的代理对象,供调用者使用,实现“偷梁换柱”;
          最后,代理根据配置,在调用业务组件前后”智能“的执行切面逻辑;
       
     4)AOP解决问题优势

          业务代码和公共代码在封装和调用方面均实现分层,解耦;
          提高了业务组件的复用度;
          提高了公共逻辑的复用度

     5)AOP与OOP的区别

          从上面看出,AOP是先按照OOP思想来解决问题的,但是传统OOP思想不能解决逻辑分层和解耦问题,于是AOP通过代理手段解决该问题。

          所以,AOP是OOP的补充,AOP=OOP+代理模式。


2. AOP应用

     1)Spring AOP组件

          目标对象:封装了业务逻辑的组件,例如Spring里的普通Service、Dao等Bean;
          代理对象:目标对象的代理,运行时动态生成(JDK动态代理和CGLIB动态代理)
          切面:      封装了公用逻辑的组件,一个切面包含三个元素:通知、切入点、引入;
          通知:      封装了公共逻辑的切面方法(前置、后置、完成、环绕、异常)
          引入:      封装了新增逻辑的组件;
          切入点:   封装了连接点匹配规则的组件,常用的匹配规则有execution/args/within;  
          连接点:   目标对象的方法;

     2)Spring AOP编程

          一个登陆服务组件,其提供login操作;

          在不改变该组件代码的前提下,加强其login操作逻辑、新增注册功能逻辑;


用户信息
package com.sample.domain;public class User {private String name;private String password;public User(){}public User(String name,String password){this.name = name;this.password = password;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String toString(){return "用户名:<"+name+">密码:<"+password+">";}}
 
登陆服务组件接口
package com.sample.service;import com.sample.domain.User;public interface LoginAndoutService {public String logIn(User user);public void logOut(User user);}

登陆服务组件实现
package com.sample.service.impl;import org.springframework.stereotype.Service;import com.sample.domain.User;import com.sample.service.LoginAndoutService;@Servicepublic class LoginAndoutServiceImpl implements LoginAndoutService {@Overridepublic String logIn(User user) {if(null == user)throw new RuntimeException("用户不能为空");return "用户<"+user.getName()+">登录成功,密码<"+user.getPassword()+">";}@Overridepublic void logOut(User user) {System.out.println("用户<"+user.getName()+">退出!");}}


登陆服务组件切面
package com.sample.aop.aspect;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.DeclareParents;import org.springframework.stereotype.Component;import com.sample.aop.introduction.LogInAndOutStrong;import com.sample.aop.introduction.impl.LogInAndOutStrongImpl;import com.sample.domain.User;@Component@Aspectpublic class LogInAndOutAspect {@DeclareParents(value="com.sample.service.*+",            defaultImpl=LogInAndOutStrongImpl.class)public static LogInAndOutStrong stronger;@Before("com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point() && args(user)")public void checkArgs(User user){if(null == user)throw new RuntimeException("用户不能为空!");System.out.println("开始,检查参数值--->"+user);}@AfterReturning(pointcut="com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()",returning="rs")public void checkResult(String rs){if( null == rs)rs = "方法为void类型,无返回值";System.out.println("返回,接收返回值--->"+rs);}@After("com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()")public void finish(){System.out.println("结束,方法调用完毕--->");}@AfterThrowing(pointcut="com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()",throwing="ex")public void handException(Exception ex){System.out.println("异常,处理异常--->"+ex);}@Around("com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()")public Object process(ProceedingJoinPoint pjp) throws Throwable{System.out.println("环绕,调用方法--->"+pjp.getKind());return pjp.proceed();}}


切面引入接口
package com.sample.aop.introduction;import com.sample.domain.User;public interface LogInAndOutStrong {public String regist(User user);}


切面引入实现
package com.sample.aop.introduction.impl;import com.sample.aop.introduction.LogInAndOutStrong;import com.sample.domain.User;public class LogInAndOutStrongImpl implements LogInAndOutStrong {@Overridepublic String regist(User user) {return "用户<"+user.getName()+">注册成功!";}}


切入点定义
package com.sample.aop.pointcut;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Component@Aspectpublic class LogInAndOutPoint {@Pointcut("execution (* com.sample.service.impl.LoginAndoutServiceImpl.log*(..))")public void logIn_Out_Point(){}}

Spring配置文件
<?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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:task="http://www.springframework.org/schema/task"xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="    http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context-3.0.xsd    http://www.springframework.org/schema/aop    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd    http://www.springframework.org/schema/task       http://www.springframework.org/schema/task/spring-task-3.0.xsd    http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 启用Spring AOP相关特性 --><aop:aspectj-autoproxy/><!-- 启用Spring 组件扫描识别特性 --><context:component-scan base-package="com.sample" /></beans>


测试类
package com.sample;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.sample.aop.introduction.LogInAndOutStrong;import com.sample.domain.User;import com.sample.service.LoginAndoutService;public class Test {/** * @param args */public static void main(String[] args) {User user = new User("张三","123456");ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");LoginAndoutService service = (LoginAndoutService)context.getBean("loginAndoutServiceImpl");System.out.println(service.logIn(user));LogInAndOutStrong stronger = (LogInAndOutStrong)service;System.out.println(stronger.regist(user));}}

测试结果
环绕,调用方法--->method-execution开始,检查参数值--->用户名:<张三>密码:<123456>返回,接收返回值--->用户<张三>登录成功,密码<123456>结束,方法调用完毕--->用户<张三>登录成功,密码<123456>用户<张三>注册成功!




0 0