AOP
:aspect oriented program,面向切面编程
主要应用:打印日志、事务管理、权限控制、访问控制;实现通用的功能,目的是简化代码,方便维护。将主业务逻辑和非业务逻辑分离出来。
下面我们用简单的例子来 阐述 AOP的打印日志功能。
1、导jar
修改pom.xml,导入jar包
<properties>
<jdk.version>1.7</jdk.version>
<charset>utf-8</charset>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.1.0.RELEASE</spring.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
导入log4j用以打印日志用。
2、修改spring配置文件的头信息
<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"
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
">
3、定义切点程序
切点程序,必须是bean组件的方法。
public class Target {
//必须是spring组件中的方法
public String save(String name)
{
System.out.println("目标程序执行成功,目标程序的参数为"+name);
return "嘿嘿";
}
}
4、定义切面程序
切面程序定义的规则
- 1、bean组件中的方法
- 2、返回类型是void
- 3、参数类型与通知类型相关
5、配置通知类型
前置通知:切面程序在切入点程序执行之前执行
定义切面程序:返回值类型为void 参数类型为JoinPoint 必须是bean组件中的方法
定义切入点程序:必须bean组件中的方法 返回值类型与参数类型不限
通知类型:指定切面程序作用在切入点程序的具体位置
后置通知:切面程序在切入点程序成功执行并返回参数之后执行
定义切面程序:返回值类型为void 参数类型为JoinPoint,Object 必须是bean组件
异常通知:切面程序在切入点程序执行抛出异常之后执行
定义切面程序:返回值类型为void 参数类型为JoinPoint,Throwable 必须是bean组件
最终通知:不管目标程序是否执行成功均会执行
定义切面程序:返回值类型为void 参数类型为JoinPoint 必须是bean组件
//切面程序
public class BeforeAspect {
//前置通知
public void doBefore(JoinPoint jp)
{
Logger logger=Logger.getLogger("BeforeAspect.class");
//获取目标函数的参数
logger.info(jp.getArgs()[0]);
//获取目标函数的反射对象
logger.info(jp.getSignature());
//获取目标对象
logger.info(jp.getTarget().getClass().getName());
logger.info("程序执行成功");
}
//后置通知
public void doAfterReturning(JoinPoint jp,Object ret)
{
System.out.println("目标函数的返回值"+ret);
System.out.println("执行中后置通知");
}
//异常通知
public void doAfterThrowing(JoinPoint jp,Throwable e)
{
System.out.println(e.getMessage());
}
//环绕通知
public void doAround(ProceedingJoinPoint pjp) {
// System.out.println("环绕前置");
Logger logger = Logger.getLogger("TargetAfterReturn.class");
double time = System.currentTimeMillis();
try {
Object ret = pjp.proceed();
// System.out.println("返回值:"+ret);
// System.out.println("环绕后置");
Thread.sleep(3000);
double runTime = (System.currentTimeMillis()-time)/1000;
// System.out.println(pjp.getSignature()+"的执行时间:"+runTime+"s");
logger.info(pjp.getSignature()+"的执行时间:"+runTime+"s");
} catch (Throwable e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
// System.out.println("环绕异常");
}finally {
// System.out.println("环绕最终");
}
}
}
下面通过配置文件,将切面程序和切点联系起来
<bean id="target" class="target.Target">
</bean>
<bean id="beforeAspect" class="aspect.BeforeAspect">
</bean>
<aop:config>
<aop:pointcut expression="execution(* target.Target.save(String))" id="targetPoint" />
<aop:aspect ref="beforeAspect">
<!-- 配置通知类型,指定为前置通知;Mehtod 为切面程序的方法名,pointcut -->
<aop:before method="doBefore" pointcut-ref="targetPoint"/>
<aop:after-returning method="doAfterReturning" pointcut-ref="targetPoint" returning="ret"/>
<aop:after-throwing method="doAfterThrowing" pointcut-ref="targetPoint" throwing="e"/>
<aop:around method="doAround" pointcut-ref="targetPoint"/>
</aop:aspect>
</aop:config>
AOP注解
1、开启自动代理,开启自动扫描。
<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"
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
">
<context:component-scan base-package="aspect,target"></context:component-scan>
<!-- 开启自动代理模式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
2、将切入点程序与切面程序声明为bean组件
3、使用注解:
@Component(value="beforeAspect")
@Aspect
public class BeforeAspect {
@Before(value="within(target.Target)")
public void doBefore(JoinPoint jp)
{
Logger logger=Logger.getLogger("BeforeAspect.class");
//获取目标函数的参数
logger.info(jp.getArgs()[0]);
//获取目标函数的反射对象
logger.info(jp.getSignature());
//获取目标对象
logger.info(jp.getTarget().getClass().getName());
logger.info("程序执行成功");
}
@AfterReturning(pointcut="within(target.Target)",returning="ret")
public void doAfterReturning(JoinPoint jp,Object ret)
{
System.out.println("目标函数的返回值"+ret);
System.out.println("执行中后置通知");
}
@AfterThrowing(pointcut="within(target.Target)",throwing ="e")
public void doAfterThrowing(JoinPoint jp,Throwable e)
{
System.out.println(e.getMessage());
}
}
网友评论