关于Spring的AOP面向切面编程
2015-06-18 19:31
771 查看
AOP,对业务的横向编程,这个思想确实不错。一个简单的实际应用:
在做项目的过程中,做了一个登陆的功能,项目做完这后,需要在用户登录完成后,进行日志管理,也就是将登录成功的用户信息存在数据库中。
这个时候就不要回过头来去源码中,在登录的那个功能里面进行写东西了,利用AOP的原理进行横向拦截大大扩展的程序的可伸缩性!
项目架构SpringMVC + Spring
这种架构项目熟悉的人都知道,Controller是由*-servlet.xml(SpringMVC)文件进行管理的,Service层则是由application.xml(Spring)文件进行管理的.
AOP有四种方式进行配置,常见的是2种,1.注解方式 2.配置文件的方式
我喜欢用配置文件的方式!
先说说对Service曾进行AOP编程吧!
Service层中:
接口:
实现:
说明:三个方法,其中有2个方法有返回值!
被插入的对象如下:
三个方法,对应切面的三个方法。
beans.xml(spring-aop核心配置文件):
对于方法的插入顺序有如下:
<aop:after method=""/> 切面方法完成以后在进行插入
<aop:after-returning method=""/> 切面方法完成返回值以后在进行插入
<aop:after-throwing method=""/> 切面方法在抛出异常的时候进行插入
<aop:around method=""/> 切面方法在开始前后进行插入(实际是自定义)
<aop:before method=""/> 切面方式在开始之前进行插入
若用到环绕,则可以在方法参数添加 ProceedingJoinPoint joinpoint
通过该对象joinpoint.process()可以执行切面方法,进而得到返回值。
测试代码如下:
/**
* 建议:
* 若目标对象有无return:
* 根据需求
* 1.若方法有return
* 则用AOP的after-return或者around
* 2.若方法没有return
* 则用AOP的after或者before
*/
以上就是对Service层代码进行切面编程-------------------------------------------------------------------------------------------------------------------
在Controller层中有一点不一样,那就是对Aop的配置位置。由于Contorller层是SpringMVC进行管理,Service层是Spring进行管理,进而生产的代理类不同,AOP生产的代理类有2种方式1.jdk的动态代理 2.cglib代理方式有 区别是前者只能对接口进行代理,后者可以对类进行代理,如果目标对象没有实现接口,则默认会采用CGLIB代理。
所以在bean.xml中配置AOP是不行的,需要在*-servlet.xml中进行配置AOP。
Controller层进行切面编程:
Controller层的代码:
同时也是切面对象
被插入的对象如下:
*.servlet.xml文件内容:
ref中的helloHelp在bean.xml文件中进行配置即可。
执行localhost::8080/项目名/aop/hello
测试都通过了!
在做项目的过程中,做了一个登陆的功能,项目做完这后,需要在用户登录完成后,进行日志管理,也就是将登录成功的用户信息存在数据库中。
这个时候就不要回过头来去源码中,在登录的那个功能里面进行写东西了,利用AOP的原理进行横向拦截大大扩展的程序的可伸缩性!
项目架构SpringMVC + Spring
这种架构项目熟悉的人都知道,Controller是由*-servlet.xml(SpringMVC)文件进行管理的,Service层则是由application.xml(Spring)文件进行管理的.
AOP有四种方式进行配置,常见的是2种,1.注解方式 2.配置文件的方式
我喜欢用配置文件的方式!
先说说对Service曾进行AOP编程吧!
Service层中:
接口:
package com.lgy.service; public interface Sleepable { void sleep(); int eat(); int play(); }
实现:
package com.lgy.service; import org.springframework.stereotype.Service; @Service public class Human implements Sleepable { @Override public void sleep() { System.out.println("人在睡觉"); } @Override public int eat() { System.out.println("dog 在 eat"); return 1; } @Override public int play() { System.out.println("play baskball"); return 1; } }
说明:三个方法,其中有2个方法有返回值!
被插入的对象如下:
package com.lgy.aop; import org.aspectj.lang.ProceedingJoinPoint; public class SleepHelper { public void afterSleep(){ System.out.println("睡醒了要穿衣服!"); } //ProceedingJoinPoint only in around public Object aroundEat(ProceedingJoinPoint joinpoint) throws Throwable { System.out.println("执行之前"); Object result = joinpoint.proceed(); //目标对象执行 System.out.println("执行之后"); return result; } public void afterReturn() { System.out.println("执行之后"); } }
三个方法,对应切面的三个方法。
beans.xml(spring-aop核心配置文件):
<!-- 配置需要被切面操作的对象 --> <bean id="sleepHelper" class="com.lgy.aop.SleepHelper"></bean> <aop:config> <aop:aspect ref="sleepHelper"> <!-- 之后进行插入 --> <aop:after method="afterSleep" pointcut="execution(* com.lgy.service.*.sleep(..))"/> <!-- around获取返回值 --> <aop:around method="aroundEat" pointcut="execution(* com.lgy.service.*.eat(..))" /> <!-- 返回之后执行 --> <aop:after-returning method="afterReturn" pointcut="execution(* com.lgy.service.*.play(..))" /> </aop:aspect> </aop:config>
对于方法的插入顺序有如下:
<aop:after method=""/> 切面方法完成以后在进行插入
<aop:after-returning method=""/> 切面方法完成返回值以后在进行插入
<aop:after-throwing method=""/> 切面方法在抛出异常的时候进行插入
<aop:around method=""/> 切面方法在开始前后进行插入(实际是自定义)
<aop:before method=""/> 切面方式在开始之前进行插入
若用到环绕,则可以在方法参数添加 ProceedingJoinPoint joinpoint
通过该对象joinpoint.process()可以执行切面方法,进而得到返回值。
测试代码如下:
/**
* 建议:
* 若目标对象有无return:
* 根据需求
* 1.若方法有return
* 则用AOP的after-return或者around
* 2.若方法没有return
* 则用AOP的after或者before
*/
package aop; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.lgy.service.Sleepable; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:/beans.xml"}) public class AopTest { @Resource(name="human") private Sleepable sleepable; @Test public void humAfter() { sleepable.sleep(); } @Test public void humAround() { int eat = sleepable.eat(); System.out.println(eat); //根据around的切面方法最终返回值 } @Test public void humafterReturn() { int i = sleepable.play(); System.out.println(i); //根据around的切面方法最终返回值 } }
以上就是对Service层代码进行切面编程-------------------------------------------------------------------------------------------------------------------
在Controller层中有一点不一样,那就是对Aop的配置位置。由于Contorller层是SpringMVC进行管理,Service层是Spring进行管理,进而生产的代理类不同,AOP生产的代理类有2种方式1.jdk的动态代理 2.cglib代理方式有 区别是前者只能对接口进行代理,后者可以对类进行代理,如果目标对象没有实现接口,则默认会采用CGLIB代理。
所以在bean.xml中配置AOP是不行的,需要在*-servlet.xml中进行配置AOP。
Controller层进行切面编程:
Controller层的代码:
同时也是切面对象
package com.lgy.controller; import javax.annotation.Resource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.lgy.service.Sleepable; @Controller @RequestMapping("/aop") public class AopController { @Resource(name="human") private Sleepable sleepable; @RequestMapping("/hello") public String hello() { System.out.println("hello world"); return "hello"; } }
被插入的对象如下:
package com.lgy.aop; public class HelloHelp { public void helloBefore() { System.out.println("AOP hellp before..."); } }
*.servlet.xml文件内容:
<?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" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <!-- 使用cglib代理 <aop:aspectj-autoproxy proxy-target-class="true" />--> <!-- 自动扫描且只扫描@Controller --> <context:component-scan base-package="com.lgy" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <!-- 注解生效 json转换--> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter" > <property name = "supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <!-- 文件上传的视图解析器,springmvc中对这个id名称写死 multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" /> <!-- 配置静态资源 --> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- controller --> <aop:config> <aop:aspect ref="helloHelp"> <!-- 之后进行插入 --> <aop:before method="helloBefore" pointcut="execution(* com.lgy.controller.*.hello(..))"/> </aop:aspect> </aop:config> </beans>
ref中的helloHelp在bean.xml文件中进行配置即可。
执行localhost::8080/项目名/aop/hello
测试都通过了!
相关文章推荐
- 【转】【九度1080题做题发现】JAVA之BigInteger
- Java 实现导出excel表 POI
- java冒泡排序
- Apriori(先验)的java实现
- java实现excel表格导出
- A Java int array example
- In Java, will the code in the finally block be called and run after a return statement is executed?
- Java并发编程-25-合并任务的结果
- Name for argument type [java.lang.String] not available......bug处理
- java 需要复习的知识点
- Java-马士兵设计模式学习笔记-工厂模式-抽象工厂模式
- Java并发编程-24-创建Fork/Join线程池
- spring4.0.5 + quartz1.8.6/2.2.1集群搭建
- Eclipse4.4.2手动安装Veloeclipse-2.0.8
- Lucene:基于Java的全文检索引擎简介
- Java System.getProperty()
- spider JAVA如何判断网页编码
- Java Math floor round ceil 函数
- spring 3 中使用注解的方式来进行任务调度
- JDK+JVM+JRE