一 配置过程
1.创建项目
2.导包
Spring的包
增加:
aopalliance
aspectjweaver
3.创建Dao层接口及实现层
4.创建通知类及要执行的通知方法
5.配置ApplicationContext.xml
配置bean
配置AOP aop:config
配置切点 aop:pointcut
id
expression "execution(针对的方法)"
配置切面 aop:aspect
id
ref
配置连接点
aop:before
aop:after
aop:after-returning
aop:around
aop:after-throwing
6.写测试类
二 示例
配置文件实现:
1.创建项目SpringAop1
2.导入需要的包
3.创建Dao层接口IUserDao
package com.hp.dao;
public interface IUserDao {
int login(String name,String password);
int div(int a,int b);
}
创建Dao层实现UserDaoImpl
package com.hp.dao.impl;
import com.hp.dao.IUserDao;
public class UserDaoImpl implements IUserDao {
@Override
public int login(String name, String password) {
if("admin".equals(name) && "123".equals(password)){
System.out.println("登录成功");
return 1;
}
else{
System.out.println("登录失败");
}
return 0;
}
@Override
public int div(int a, int b) {
int res=a/b; //b=0时抛出异常
return res;
}
}
4.创建通知类及要执行的通知方法LogAdvice
package com.hp.advice;
import org.aspectj.lang.JoinPoint;
public class LogAdvice {
public void before(JoinPoint jp){
/*
* 如何才能知道调用的是哪一个方法
* 给before方法添加一个参数JoinPoint
*/
String methodName = jp.getSignature().getName(); //获取方法名
Object[] args = jp.getArgs(); //获取参数
System.out.println("前置通知");
System.out.println("将要执行:"+methodName+"方法");
System.out.println("参数列表:");
for (Object object : args) {
System.out.println(object);
}
}
public void after(JoinPoint jp){
String methodName = jp.getSignature().getName();
System.out.println(methodName + "方法执行结束");
System.out.println("后置通知");
}
public void afterReturning(Object res) throws Throwable{
System.out.println("返回值:"+res);
System.out.println("返回通知");
}
public void afterThrowing(Exception ex){
System.out.println("异常信息:"+ex.getMessage());
System.out.println("分母不能为0");
}
}
5.配置ApplicationContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.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-4.1.xsd">
<!-- 声明bean -->
<bean id="IUserDao" class="com.hp.dao.impl.UserDaoImpl" ></bean>
<bean id="logAdvice" class="com.hp.advice.LogAdvice"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切入点 -->
<!-- 第一个*表示访问符和返回类型任意,括号里的两个点表示任意参数 -->
<aop:pointcut expression="execution(* com.hp.dao.*.*(..))" id="logPoint" />
<!-- 配置切面 -->
<aop:aspect id="logAspect" ref="logAdvice" >
<!-- 配置连接点 -->
<aop:before method="before" pointcut-ref="logPoint" />
<aop:after method="after" pointcut-ref="logPoint"/>
<aop:after-returning method="afterReturning" pointcut-ref="logPoint" returning="res"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="logPoint" throwing="ex"/>
</aop:aspect>
</aop:config>
</beans>
6.写测试类MainTest
package com.hp.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hp.dao.IUserDao;
public class MainTest {
@Test
public void login() throws Exception{
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
IUserDao iUserDao = (IUserDao) context.getBean("IUserDao");
iUserDao.login("admin", "123");
System.out.println("-------------");
iUserDao.div(1, 0);
}
}
7.运行结果:
前置通知
将要执行:login方法
参数列表:
admin
123
登录成功
login方法执行结束
后置通知
返回值:1
返回通知
-------------
前置通知
将要执行:div方法
参数列表:
1
0
div方法执行结束
后置通知
异常信息:/ by zero
分母不能为0
8.项目结构:
注解实现
1.创建项目SpringAop2
2.导入需要的包(同上)
3.创建Dao层接口IUserDao
package com.hp.dao;
public interface IUserDao {
int login(String name,String password);
int div(int a,int b);
}
创建Dao层实现UserDaoImpl
package com.hp.dao.impl;
import org.springframework.stereotype.Repository;
import com.hp.dao.IUserDao;
@Repository("IUserDao")
public class UserDaoImpl implements IUserDao {
@Override
public int login(String name, String password) {
if("admin".equals(name) && "123".equals(password)){
System.out.println("登录成功");
return 1;
}
else{
System.out.println("登录失败");
}
return 0;
}
@Override
public int div(int a, int b) {
int res=a/b; //b=0时抛出异常
return res;
}
}
4.创建通知类及要执行的通知方法LogAdvice
package com.hp.advice;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component //(把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
public class LogAdvice {
@Pointcut("execution(* com.hp.dao.*.*(..))")
private void anyMethod(){} //声明一个切入点,anyMethod为切入点名称
@Before("anyMethod()")
public void before(JoinPoint jp){
/*
* 如何才能知道调用的是哪一个方法
* 给before方法添加一个参数JoinPoint
*/
String methodName = jp.getSignature().getName();//获取方法名
Object[] args = jp.getArgs();//获取参数
System.out.println("前置通知");
System.out.println("将要执行:"+methodName+"方法");
for (Object object : args) {
System.out.println(object);
}
}
@After("anyMethod()")
public void after(JoinPoint jp){
String methodName = jp.getSignature().getName();
System.out.println(methodName+"方法执行结束");
System.out.println("后置通知");
}
@AfterReturning(pointcut ="anyMethod()", returning="res")
public void afterReturning(Object res) throws Throwable{
System.out.println("方法返回值:"+res);
System.out.println("返回通知");
}
@AfterThrowing(pointcut = "anyMethod()", throwing="ex")
public void afterThrowing(Exception ex){
System.out.println("异常信息:"+ex.getMessage());
System.out.println("分母不能为0");
}
}
5.配置ApplicationContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.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-4.1.xsd">
<!-- spring注解 -->
<context:component-scan base-package="com.hp.dao,com.hp.advice" />
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
6.写测试类MainTest
package com.hp.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hp.dao.IUserDao;
public class MainTest {
@Test
public void login() throws Exception{
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
IUserDao iUserDao = (IUserDao) context.getBean("IUserDao");
iUserDao.login("admin", "123");
System.out.println("-------------");
iUserDao.div(1, 0);
}
}
7.运行结果:前置通知
将要执行:login方法
参数列表:
admin
123
登录成功
login方法执行结束
后置通知
返回值:1
返回通知
-------------
前置通知
将要执行:div方法
参数列表:
1
0
div方法执行结束
后置通知
异常信息:/ by zero
分母不能为0
8.项目结构:
三 问题研究
1. 在返回通知中,如何获取返回值?
xml中<aop:after-returning method="afterReturning" pointcut-ref="logPoint" returning="res"/>
Advice中传递一个Object类型的res参数
2. 在异常通知中,如何获取出现的异常?
xml:<aop:after-throwing method="afterThrowing" pointcut-ref="logPoint" throwing="ex"/>
Advice中传递一个Exception类型的ex参数
Advice中ex.getMessage()
3. 当异常出现时,返回通知和后置通知还会执行吗?
返回通知不会执行,后置通知会执行
4. 当后置通知与返回通知同时存在时,哪一个先执行呢?
执行顺序按照在xml配置文件中的配置顺序执行
四 XML配置方式与注解方式对比
1. 使用注解时,需要在XML配置文件中添加<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2. @ Component注解,相当于配置文件中的,<bean >
3. @ Pointcut注解,相当于配置文件中的,<aop:pointcut>
4. @ Aspect注解,相当于配置文件中的, <aop:aspect>
5. @ Before注解,相当于配置文件中的.<aop:before> after afterrunning afterthrowing around
注:异常通知,比较常用, 我们在编写Dao层和Service层时,可以完全不作异常处理,而且创建一个专门的异常通知切面,由这个异常处理通知类专门负责处理各种异常。