AOP: Aspect Oriented Programming 面向切面编程
OOP: Object Oriented Programming 面向对象编程
一、AOP简介
AOP是基于OOP基础之上新的编程思想,OOP面向的主要是对象是类,而AOP面向的主要对象是切面,一般用来进行处理日志、安全管理、事务管理等。AOP是Spring中重要的核心点,ioc容器没有依赖AOP,但是AOP提供了很强大的功能。
简单来说:AOP就是在程序运行期间,在不修改原有代码的情况下,给程序添加额外功能的技术,这种编程方式叫做AOP。
public class UserServiceImpl implements UserService{
@Override
public User get(Integer id) {
System.out.println("查询");
return new User();
}
/*
System.out.println("日志");
System.out.println("查询");
return new User();
*/
@Override
public void add(User user) {
System.out.println("添加");
}
@Override
public void del(Integer id) {
System.out.println("删除");
}
@Override
public void upt(User user) {
System.out.println("修改");
}
}
这个代码非常简单,但是如果需要添加日志输出,同时修改会变得麻烦,这里可以使用代理的方式来实现添加日志。
代理是一种设计模式,AOP底层是通过动态代理来实现的。
1)静态代理
2)动态代理
jdk动态代理:需保证被代理的类实现了接口
cglib动态代理:无需接口
代理类
public class UserHandler implements InvocationHandler {
// 被代理的对象
Object target;
public UserHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
LoggUtil.start(method,args);
//执行目标
result = method.invoke(target, args);
LoggUtil.stop(method,args);
} catch (Exception e) {
LoggUtil.logException(method,e);
} finally {
LoggUtil.end(method);
}
return result;
}
}
测试添加日志
public class Test {
@org.junit.Test
public void Test(){
UserService userService =(UserService) createProxy(new UserServiceImpl());
userService.get(1);
}
public static Object createProxy(Object object){
ClassLoader classLoader = object.getClass().getClassLoader();
Class<?>[] classes = object.getClass().getInterfaces();
InvocationHandler handler = new UserHandler(object);
// 动态创建代理类
Object o = Proxy.newProxyInstance(classLoader, classes, handler);
return o;
}
}
日志类
public class LoggUtil {
public static void start(Method method,Object ... objects){
System.out.println(method.getName()+"方法开始执行,参数是:"+ Arrays.asList(objects));
}
public static void stop(Method method,Object ... objects){
System.out.println(method.getName()+"方法执行结束,参数是:"+ Arrays.asList(objects));
}
public static void logException(Method method,Exception e){
System.out.println(method.getName()+"方法出现异常:"+ e.getMessage());
}
public static void end(Method method){
System.out.println(method.getName()+"方法执行结束");
}
}
以上为jdk动态代理的实现,在spring中可以不用编写这样复杂的代码,只需要利用AOP,就可以实现,当然,AOP底层依赖的也是动态代理
AOP术语
- 切面(Aspect): 指关注点模块化,这个关注点可以横切多个对象
- 连接点(Join point):在程序执行过程中某个特定的点
- 通知(Advice):在切面某个特定的连接点上执行的动作
- 切点(Pointcut):匹配连接点的断言,通知和切点表达式相关联,并在满足这个切点的连接点上运行
- 引入(Introduction):声明额外的方法或者某个类型的字段
- 目标对象(Target object):被一个或者多个切面所通知的对象
- AOP代理(AOP proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。
- 织入(Weaving):把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象的过程。
AOP通知类型
- 前置通知(Before advice):在连接点之前运行但无法阻止执行流程进入连接点的通知。
- 后置返回通知(After returning advice):连接点正常完成后执行。
- 后置异常通知(After throwing advice):方法抛出异常时执行
- 后置通知(After advice):当连接点退出的时候执行的通知(无论是正常返回还是异常退出)。
- 环绕通知(Around Advice):环绕连接点的通知,最强大的通知类型。可以在方法调用前后完成自定义行为,选择是否继续执行连接点或直接返回自定义的返回值或抛异常结束。
AOP实现
@Component
@Aspect
public class LoggUtil {
@Before( "execution(* com.lc.User..*.*(..))")
public static void before(){
System.out.println("方法前");
}
@After("execution(* com.lc.User..*.*(..))")
public static void after(){
System.out.println("方法前");
}
@AfterThrowing("execution(* com.lc.User..*.*(..))")
public static void afterException(){
System.out.println("方法异常");
}
@AfterReturning("execution(* com.lc.User..*.*(..))")
public static void afterRet(){
System.out.println("方法异常");
}
}
@Test
public void Test02(){
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("classpath:/spring_aop.xml");
UserService bean = (UserService)ioc.getBean("userServiceImpl");
UserService be = ioc.getBean(UserService.class);
bean.get(1);
}
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描包-->
<context:component-scan base-package="com.lc.User" >
</context:component-scan>
<!--开启AOP-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
T:XY