spring中的AOP编程思想详解

来源:互联网 发布:matlab 矩阵添加行 编辑:程序博客网 时间:2024/06/05 05:23

一.AOP编程思想介绍

1.servlet的AOP体现:

AOP意思就是面向切面编程,可以用一句话概况AOP编程思想,即横向重复,纵向抽取。我们知道,软件工程一个基本原则就是代码复用,为了实现这个目标,我们可以用类,用方法,同样,AOP也是代码复用的一种方式。我们现在用下面这样一种例子来具体解释什么叫做面向切面编程。熟悉 java web的朋友可能清楚,我们在编写servlet需要解决一系列的乱码问题,此时可以用filter一次性解决servlet乱码问题。此处的servlet中的乱码问题就是横向重复,而filter就是纵向抽取。可用下图表示此个例子。

2.SSH框架中的AOP思想体现

在SSH框架中,一个典型的例子就是service层中的事务管理,没一个service层都需要实现事务管理的代码,这就是所谓横向重复,spring能够为容器中的对象生成动态代理对象(spring中使用动态代理技术实现AOP),通过这个代理对象能够纵向管理事务操作。

具体如图解释。


二.spring实现AOP的原理解析

基本原理:通过生成代理对象,对原来的方法进行增强。根据生成对象的方式不同,分为两类。一类为动态代理,要求被代理的对象必须实现接口。一类为cglib代理,可以对任何类实现代理,原理为继承代理,若类被final修饰,则无法代理。

方式一解析:动态代理方式实现一个类中的方法

现在假设dao层有一个类UserDao,这个类有一个方法Save用来保存用户数据,一般在保存数据前,我们需要进行权限判断,而这个权限判断是为横向的重复操作,所以可以用AOP思想把它纵向抽取,然后通过动态代理技术把save方法增强,使其在进行保存之前进行权限判断。下面是动态代理的代码实现。

public class MyJDKProxy implements InvocationHandler//动态代理必须实现此接口 {private UserDao userDao;public MyJDKProxy(UserDao userDao) {this. userDao = userDao;}
//通过java中的代理类Proxy,生成UserDao的代理对象:public UserDao createProxy(){UserDao userDaoProxy = (UserDao)Proxy. newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(), this);return userDaoProxy;}
//此时模拟对方法进行增强,加入权限判断的代码@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable{if("save".equals(method.getName())){System. out.println("权限判断================");}return method.invoke(userDao, args);}}

方式二解析:Cglib动态代理技术生成一个代理对象。

Cglib是第三方的代理技术,被spring集成使用,原理是对目标对象进行继承代理,底层是字节码增强技术,生成当前类的子类对象。现在为上面的情况为save方法加入权限判断代码。Cglib动态代理对象的方式如下

public class MyCglibProxy implements MethodInterceptor{private CustomerDao customerDao;public MyCglibProxy(CustomerDao customerDao){this. customerDao = customerDao;//获得需要增强方法的目标类}// 生成代理的方法:public CustomerDao createProxy(){// 创建 Cglib 的核心类:Enhancer enhancer = new Enhancer();// 设置父类:enhancer.setSuperclass(CustomerDao. class);// 设置回调:enhancer.setCallback(this);// 生成代理:
CustomerDao customerDaoProxy = (CustomerDao) enhancer.create();return customerDaoProxy;}@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxymethodProxy) throws Throwable {if("save".equals(method.getName())){Object obj = methodProxy.invokeSuper(proxy, args);System. out.println("权限判断================");return obj ;}return methodProxy.invokeSuper(proxy, args);}}

三.spring中AOP开发详解

1.spring中AOP开发中的相关术语

Joinpoint(连接点): 目标对象中,所有可以增强的方

Pointcut(切入点): 目标对象所有已经增强的方法

Advice(通知/增强): 增强的代码

前置通知 :在目标方法执行之前执行.
后置通知 :在目标方法执行之后执行
环绕通知 :在目标方法执行前和执行后执行
异常抛出通知:在目标方法执行出现 异常的时候 执行
最终通知 :无论目标方法是否出现异常 最终通知都会 执行.

Target(目标对象): 代理的目标对象

Weaving(织入): 将通知应用到切入点的过程,spring 采用动态代理织入

Proxy(代理) : 将通知织入到目标对象后,形成代理对象。
Aspect(切面):切入点+通知

2.spring使用XML进行AOP的开发

spring内部已经实现了动态代理,在实际开发时,只需要准备后通知,然后在主配置文件中把通知配置到需要增强的方法中即可。
步骤一,导入AOP开发中所需要的jar包(四个)
1.spring-aspects-4.2.4.RELEASE.jar
2.spring-aop-4.2.4.RELEASE.jar
3.  com.springsource.org.aopalliance-1.0.0.jar

4. com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

步骤二,准备好目标对象

创建接口和类:public interface UserService {public void save();public void update();public void delete();public void find();}public class UserServiceImpl implements UserService{@Overridepublic void save() {System. out.println("保存用户...");}@Overridepublic void update() {System. out.println("修改用户...");}@Overridepublic void delete() {System. out.println("删除用户...");}@Overridepublic void find() {System. out.println("查询用户...");}}
步骤三,准备通知

public class Myadvice{public void before(){System.out.println("前置增强")}public void afterReturning(){System.out.println("后置增强,出现异常不会调用")}public Object around(ProceedingJoinPoint pjp)throw Throwable{System. out.println("环绕通知前的通知===========");Object proceed=pjp.proceed();//调用目标方法System. out.println("环绕通知后的通知===========");return proceed;}public void afterException(){System. out.println("出现异常调用===========");}public void after(){System. out.println("后置增强,出现异常依然调用===========");}}

步骤四.配置讲通知织入目标对象中

目标类的配置

<! -- 目标类================ --><bean id="orderDao" class="com.cai.spring..UserServiceImpl"></bean>
切面类的配置:
<! -- 配置切面类 --><bean id="myAspectXml" class="com.cai.spring.MyAdvice"></bean>

AOP的配置:

<aop:config>
<!-- 目标类的引入,可以用通配符-->
<aop:pointcut expression="execution(*com.spring.UserServiceImpl.*(..))" id="pointcut1"/><! -- 配置切面 --><aop:aspect ref="myAdvice">
<aop:before method="before" point-ref"pointcut1"/>
<aop:aspect method="afterReturninf" point-ref"pointcut1"/>
...其他几种通知配置如以上两种类似</aop:aspect></aop:config>
至此,完成spring中AOP的XML全部配置

3.spring使用注解方式配置AOP

前四步与XML配置方式完全一致:导包--准备目标对象--准备通知--把目标对象和通知对象配置到主配置文件

区别在于:此种方式在在编写通知方法时用注解方式进行配置。以前置通知与后置通知为例。

@Aspect//表明该类是一个通知类public class MyAdvice {//引入目标对象,这句话意思是方法切入点,execution为执行的意思,*代表任意返回值,然后是包名,
.*意思是包下面的所有子包。(..)代表各种方法.@Pointcut("execution(*com.cai.service.ServiceImpl.*(...))")public void pointcut1{}// 前置增强@Before("Myadvice.pointcut1()")public void before(){System. out.println("前置增强===========");}@AfterReturning("Myadvice.pointcut1()")public void afterReturning(){System. out.println("后置通知,出现异常不会调用===========");}
.........其他几种类型的通知类似配置
四.总结

AOP思想是spring中至关重要的编程思想,也是spring如此强大的原因之一,使用AOP思想,可以完成如事务控制,日志记录,权限校验一一系列工作,方便开发进行。