说到spring,我们最容易联想到的是金典时尚的IOC与AOP.
IOC全称Inversion of Control,解释为控制反转或依赖注入,主要通过容器完成对象的创建和自动注入,与利用Java反射功能实例化bean与bean的依赖关系,使代码中少了很多显示的get,set 方法;,本文将不做详细讨论.
AOP全称Aspect Orient Programming,解释为面向切面编程。是对OOP(Object Orient Programming)面向对象编程的一种补充,当我们需要为分散的对象引入公共行为,比如权限控制,日志打印的时候,用简单的面向对象思想会显得有些负责,会存在比较多的重复代码和较高的代码耦合度。用AOP则恰恰相反,他将那些与业务无关多个类的公共行为,却为业务模块所共同调用的逻辑或责任使用动态JDK代理技术封装到一个可重用模块,在AOP中称为横切面组件Component Aspect,横切面组件中各种可重复利用的代码逻辑,如@Before 、@Around、@AfterReturning、@AfterThrowing、@After,具体将在后面实例代码中进行介绍。横切面是定义公共方法公共行为的地方,那么竟然有定义之处就一定会有定义切入点Pointcut的地方,所谓切入点就是定义项目中哪些包下的哪些类哪些方法会被横切面拦截,Pointcut中会采用指定的表达式进行定义,常见的表达式类型有:execution、within、this、target、@annotation等,详见后面的示例。
示例1 :基于execution最常见的切入点类型
xml:配置aop动态代理命名空间
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.j2ee.*" />
<aop:aspectj-autoproxy />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
定义切入点:指定包下的所有test开头的公共方法,任何参数任何返回值
public class PointCuts {
@Pointcut("execution(public * com.j2ee.spring.spring_aop.SpringAopMainController.test*(..))")
public void aopDemo() {
System.out.println("aopDemo-----------------------------");
}
}
定义切面:
Aspect切面就是我们定义增加处理的地方,增强处理会用不同的方法注解区分调用的先后顺序,这些注解都有一个value参数,参数值是切入点的方法路径。
@Around:是增强处理的开始,它会在真正调用目标方法前执行,当代码执行到 pjp.proceed();时会进入@Before注解方法的增强处理
@Before:当@Around增强代码执行到 pjp.proceed();时会进入此注解方法的增强处理,在此就可以对切入点目标方法进行额外的增强处理,比如代码中的设置school session值。@Before增强处理执行完接下来就会执行切入点的目标方法了,代码后面会黏出来。目标方法执行的时候,假如执行正常,上面的@Around增强处理pjp.proceed()后面的代码还会继续执行,执行完就进入 @After的增强处理;假如执行过程中抛出了异常,pjp.proceed()后面的代码就不会继续执行了,直接会跳到@After的增强处理
@After:此增强处理注解的方法主要做执行完切入点目标方法的成功或失败跳转,假如目标方法执行成功,没有抛出异常,则会跳转到@AfterReturning的收尾增强处理;假如目标方法执行失败抛出异常,则会跳转到 @AfterReturning的收尾增强处理。
@AfterReturning:假如目标切入点方法执行成功的最后增强处理,代码中有打印目标切入点方法的参数,没有参考意义。
@AfterReturning:假如目标切入点方法执行失败的最后增强处理。
@Component
@Aspect
public class Aspect1 {
@Before(value = "com.j2ee.spring.spring_aop.PointCuts.aopDemo()")
public void before(JoinPoint joinPoint) {
System.out.println("[Aspect1] before advise");
Object[] objects=joinPoint.getArgs();
HttpServletRequest request= (HttpServletRequest) objects[0];
request.getSession().setAttribute("school","清华大学");
}
@Around(value = "com.j2ee.spring.spring_aop.PointCuts.aopDemo()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("[Aspect1] around advise 1");
pjp.proceed();
System.out.println("[Aspect1] around advise2");
}
@AfterReturning(value = "com.j2ee.spring.spring_aop.PointCuts.aopDemo()")
public void afterReturning(JoinPoint joinPoint) {
Object[] objects=joinPoint.getArgs();
HttpServletRequest request= (HttpServletRequest) objects[0];
String name=request.getParameter("name");
String age=request.getParameter("age");
System.out.println("[Aspect1] afterReturning advise---->name:"+name+";age:"+age);
}
@AfterThrowing(value = "com.j2ee.spring.spring_aop.PointCuts.aopDemo()")
public void afterThrowing(JoinPoint joinPoint) {
System.out.println("[Aspect1] afterThrowing advise");
}
@After(value = "com.j2ee.spring.spring_aop.PointCuts.aopDemo()")
public void after(JoinPoint joinPoint) {
System.out.println("[Aspect1] after advise");
}
}
示例controller方法:
@Controller
@RequestMapping("springaopmaincontroller")
public class SpringAopMainController {
@RequestMapping(value = "test2", method = RequestMethod.POST)
@ResponseBody
public String test2(HttpServletRequest request, HttpServletResponse response) throws Exception {
String name=request.getParameter("name");
String age=request.getParameter("age");
String school= request.getSession().getAttribute("school")==null?
"":request.getSession().getAttribute("school").toString();
System.out.println("我是中国人--->name:"+name+";age:"+age+";school:"+school);
//抛出异常了
if ("李四".equals(name)){
throw new Exception();
}
JSONObject jsonObject=new JSONObject();
jsonObject.put("name","李四");
jsonObject.put("age",100);
return jsonObject.toString();
}
}
jsp页面的代码
<html>
<head>
<base href="<%=basePath%>">
<title>Title</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
function test1(name) {
$.ajax( {
type : "POST",//(默认: "GET") 请求方式 ("POST" 或 "GET"),
url : "<%=basePath2%>springaopmaincontroller/test2.do",
data : {name:name,age:30},
async: false,
dataType : "json",
success : function(data) {
alert("success-->name:"+data.name+";age:"+data.age)
} ,
error:function(data){
alert("error-->name:"+data.name+";age:"+data.age)
}
});
}
</script>
</head>
<body style="text-align: left;margin-top: 20px">
<input type="button" onclick="test1('张三')" value="测试1_正常执行的情况"/>
<input type="button" onclick="test1('李四')" value="测试1_存在异常的情况"/>
</body>
</html>
执行结果打印的情况:
当执行正常时打印结果:
当执行出现异常时打印结果:
示例2:当切入点是大名鼎鼎的实用可信赖的注解时的情况
注解代码:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AdressAnnotation {
String province();
String city();
boolean isforeign();
int countyNum();
}
切面和切入点代码:
@Aspect
public class AddressAspect1 {
@Pointcut(value = "@annotation(com.j2ee.spring.spring_aop.example2_annotation.AdressAnnotation)" )
public void addressPointCuts(){}
@Before(value= "addressPointCuts() && @annotation(adressAnnotation)",argNames="adressAnnotation")
public void before(AdressAnnotation adressAnnotation) {
System.out.println("示例2切面before增强方法:"+adressAnnotation.province()+" "+adressAnnotation.city()
+" "+adressAnnotation.isforeign()+" "+ adressAnnotation.countyNum());
System.out.println("[AddressAspect1] before advise");
}
}
带注解的控制器代码:
@Controller
@RequestMapping("addresscontroller")
public class AddressController {
@RequestMapping("getaddress")
@AdressAnnotation(province ="福建省",city = "龙岩市",isforeign = false,countyNum = 30)
@ResponseBody
public String getAddress(HttpServletRequest request, HttpServletResponse response){
System.out.println("示例2控制器方法");
return "调用成功";
}
}
额外实例化bean代码:
<bean class="com.j2ee.spring.spring_aop.example2_annotation.AddressAspect1"/>
jsp页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"+request.getServerName() + ":" + request.getServerPort() + path + "/style/";
System.out.println("basePath:"+basePath);
String basePath2 = request.getScheme() + "://"+request.getServerName() + ":" + request.getServerPort() + path + "/";
System.out.println("basePath2:"+basePath2);
%>
<html>
<head>
<base href="<%=basePath%>">
<title>Title</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
function test4() {
$.ajax( {
type : "POST",//(默认: "GET") 请求方式 ("POST" 或 "GET"),
url : "<%=basePath2%>addresscontroller/getaddress.do",
data :'',
async: false,
dataType : "json",
success : function(data) {
alert("success:"+data)
} ,
error:function(data){
alert("error:"+data)
}
});
}
</script>
</head>
<body style="text-align: left;margin-top: 20px">
<input type="button" onclick="test4()" value="测试4_Annotation切入点"/><br><br>
</body>
</html>
运行示例代码控制台打印的结果::