引言
- 什么是AOP?(面试题),单纯回答面向切面编程不能令面试官满意,最好结合自己的理解。
AOP概述
- AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP(Obecj-Oriented Programming,面向对象编程)的补充。
- 面向对象 — 纵向继承机制
- 面向切面 — 横向抽取机制
- AOP编程的主要操作对象是切面(aspect),而切面用于模块化横切关注点(即公共功能Util)
- 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能应用在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的类里—这样的类我们通常称之为“切面”。
- AOP的好处:(1)每个事务逻辑位于一个位置,代码不分散,便于维护和升级;(2)业务模块更简洁,只包含核心业务代码;
- AOP的实现就是依赖动态代理
- AOP图解
AOP术语
- 横切关注点:从每个方法中抽取出来的同一类非核心业务
- 切面(Aspect):封装横切关注点信息的类,每个关注点体现为一个通知方法。
- 通知(Advice): 切面必须要完成的各个具体工作。(包括:前置通知、后置通知、返回通知、异常通知、环绕通知)
- 目标(Target): 被通知的对象。
- 代理(Proxy): 向目标对象应用通知之后创建的代理对象
- 连接点(Joinpoint): 横切关注点在程序代码中的具体实现,对应程序执行的某个特定位置。例如:类某个方法调用前、调用后、方法捕获异常后等。在应用程序中可以使用横纵两个坐标来定位一个具体的连接点:
手把手通过实践理解(简易计算器)
- 创建一个Java工程,然后自建conf文件夹(放xml配置文件),lib(放jar包)
- 需要导入的jar包
- com.springsource.net.sf.cglib-2.2.0.jar
- com.springsource.org.aopalliance-1.0.0.jar
- com.springsource.org.aspectj.weaver-1.6.4.RELEASE.jar
- commons-logging-1.1.1.jar
- spring-aop-4.0.0.RELEASE.jar
- spring-aspects-4.0.0.RELEASE.jar
- spring-beans-4.0.0.RELEASE.jar
- spring-context-4.0.0.RELEASE.jar
- spring-core-4.0.0.RELEASE.jar
- spring-expression-4.0.0.RELEASE.jar
- conf配置文件如下:
<?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"
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="com.test"/>
<aop:aspectj-autoproxy/>
</beans>
- 业务逻辑层
package com.test.Service;
public interface MathService {
//加减乘除
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
- Impl实现层
package com.test.Impl;
import com.test.Service.MathService;
import org.springframework.stereotype.Service;
@Service
public class MathImpl implements MathService {
private int result;
public int add(int i, int j){
this.result = i + j;
return result;
}
public int sub(int i, int j){
this.result = i - j;
return result;
}
public int mul(int i, int j){
this.result = i * j;
return result;
}
public int div(int i, int j){
this.result = i / j;
return result;
}
}
- 所谓的横切关注点(公共功能:比如日志)
package com.test.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyLoggerAspect {
@Before(value="execution(* com.test.Impl.MathImpl.*(..))")
public void beforeMethod(){
System.out.println("前置通知");
}
@After(value="execution(* com.test.Impl.MathImpl.*(..))")
public void afterMethod(){
System.out.println("后置通知");
}
@AfterReturning(value="execution(* com.test.Impl.MathImpl.*(..))", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("method:"+methodName+"\tresult:" + result);
}
@AfterThrowing(value="execution(* com.test.Impl.MathImpl.*(..))", throwing = "ex")
public void afterThrowingMethod(ArithmeticException ex){
System.out.println("异常信息: " + ex);
}
/**
* 这里是 环绕通知 相当于把前面都集成起来了,
* 你可以试试把前面都注释掉,只用这一段
* @Around(value="execution(* com.test.Impl.MathImpl.*(..))")
* public Object aroundMethod(ProceedingJoinPoint joinPoint){
* try {
* System.out.println("前置通知");
* joinPoint.proceed();
* } catch (Throwable e) {
* e.printStackTrace();
* System.out.println("异常通知");
* }finally {
* System.out.println("后置通知");
* }
* //为什么这里不返回null?因为接收对象是Integer
* return -1;
* }
*/
}
- 测试切面的优先级
package com.test.Logger;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(1)//@order的值越小优先级越高,默认值为Int的最大值
public class TestAspect {
@Before(value="execution(* com.test.Impl.MathImpl.*(..))")
public void before(){
System.out.println("我优先级更高==》前置通知");
}
}
- 测试类
package com.test;
import com.test.Service.MathService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyProxyTest {
public static void main(String[] args) {
ApplicationContext ac =new ClassPathXmlApplicationContext("config.xml");
MathService mathService = ac.getBean("mathImpl",MathService.class);
mathService.div(4,2);
}
}
【以上就是简易计算器的所有代码】