一、AOP概述
1)在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
2)AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
3)利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
4)AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
5)经典应用:事务管理、性能监视、安全检查、缓存 、日志等【画图】
6)Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
7)AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
二、AOP的实现
2.1 动态代理
a.aop底层将采用代理机制进行实现。
b.接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
c.实现类:spring 采用 cglib字节码增强。
2.2 术语
1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3.PointCut 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。
1.4 手动代理
1.4.1 JDK动态代理
package com.sinosun.springbootdemo.core.spring.aop.dynamicproxy;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 动态代理源码:接口 + 实现类
*/
@Configuration
@ComponentScan(value = {"com.sinosun.springbootdemo.core.spring.aop.dynamicproxy"})
public class Config16 {
/**
* 1.target:目标类,需要被代理的类。例如:UserService
* 2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
* 3.PointCut 切入点:已经被增强的连接点。例如:addUser()
* 4.advice 通知/增强,增强代码。例如:after、before
* 5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
* 6.proxy 代理类
* 7. Aspect(切面): 是切入点pointcut和通知advice的结合
* 一个线是一个特殊的面。
* 一个切入点和一个通知,组成成一个特殊的面。
*/
}
package com.sinosun.springbootdemo.core.spring.aop.dynamicproxy;
public interface IUserService {
void addUser();
void deleteUser();
void updateUser();
String selectUserName(int id);
}
package com.sinosun.springbootdemo.core.spring.aop.dynamicproxy;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
/**
* 切面类
* 增加代码与切入点的结合
*/
@Component
public class MyAspect {
public void before() {
System.out.println("切面类...开启事务");
}
public void after() {
System.out.println("切面类...提交事务");
}
}
package com.sinosun.springbootdemo.core.spring.aop.dynamicproxy;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@Component
public class UserServiceFactory {
@Autowired
private UserServiceImpl userService;
@Autowired
private MyAspect aspect;
public IUserService createUserImpl() {
// 1.创建目标对象target
IUserService iUserService = userService;
// 2.声明切面类对象
MyAspect myAspect = aspect;
// 3.把切面类的两个方法应用到目标类
//3.1 创建JDK代理
/*newProxyInstance(
ClassLoader loader,//类加载器
Class<?>[] interfaces,// 接口,接口的方法会被拦截
InvocationHandler h//) // 处理方法*/
IUserService proxyUserService = (IUserService) Proxy.newProxyInstance(UserServiceFactory.class.getClassLoader(),
iUserService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//开启事务
myAspect.before();
// 业务方法的返回值
iUserService.addUser();
iUserService.selectUserName(2);
Object result = method.invoke(iUserService, args);
System.out.println("拦截返回值:" + result);
//关闭事务
myAspect.after();
return result;
}
});
return proxyUserService;
}
}
package com.sinosun.springbootdemo.core.spring.aop.dynamicproxy;
import org.springframework.stereotype.Component;
@Component
public class UserServiceImpl implements IUserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
@Override
public void updateUser() {
System.out.println("修改用户");
}
@Override
public String selectUserName(int id) {
System.out.println("查询用户");
return "zhansan";
}
}
@Test
public void test4() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Config16.class);
System.out.println("容器加载完成");
String[] name = app.getBeanDefinitionNames();
for (String s : name) {
System.out.println("容器器中的beanId--->:" + s);
}
UserServiceFactory userServiceFactory = app.getBean(UserServiceFactory.class);
IUserService iUserService = userServiceFactory.createUserImpl();
iUserService.selectUserName(1);
}
2.2 cglib 增强字节码
没有接口,只有实现类。
采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。
package com.sinosun.springbootdemo.core.spring.aop.cglibproxy;
import org.springframework.stereotype.Component;
/**
* 切面类
* 增加代码与切入点的结合
*/
@Component
public class MyAspect {
public void before() {
System.out.println("CGLIB切面类...开启事务");
}
public void after() {
System.out.println("CGLIB切面类...提交事务");
}
}
package com.sinosun.springbootdemo.core.spring.aop.cglibproxy;
import org.springframework.stereotype.Component;
@Component
public class StudengService {
public void add(String name) {
System.out.println("add student:" + name);
}
public void delete(int uuid) {
System.out.println("delete student" + uuid);
}
public void update() {
System.out.println("update student");
}
}
package com.sinosun.springbootdemo.core.spring.aop.cglibproxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
public class StudentServiceFactory {
@Autowired
StudengService service;
@Autowired
MyAspect aspect;
public StudengService createStudentServiceImpl() {
// 1.创建目标对象target
final StudengService studengService = service;
// 2.声明切面类对象
MyAspect myAspect = aspect;
// 3.增加对象
Enhancer enhancer = new Enhancer();
// 4.设置父类
enhancer.setSuperclass(studengService.getClass());
// 设置回调【拦截作用】
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
/*
采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。
obj:该对象是studengService的子类
class service.business.cglibproxy.StudengService$$EnhancerByCGLIB$$cb8ff36e
class org.springframework.cglib.proxy.MethodProxy
拦截*/
// 开启事务
myAspect.before();
System.out.println("拦截");
//执行目标类的方法
//Object result = method.invoke(studengService, objects);
/**
* 和studengService对象解耦
* 执行代理类的方法(目标类和代理类是父子关系)
*/
Object result = methodProxy.invokeSuper(obj, objects);
myAspect.after();
return result;
}
});
StudengService cglibStudengService = (StudengService) enhancer.create();
return cglibStudengService;
}
}
package com.sinosun.springbootdemo.core.spring.aop.cglibproxy;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* CGLIB:实现类
*/
@Configuration
@ComponentScan(value = {"com.sinosun.springbootdemo.core.spring.aop.cglibproxy"})
public class Config17 {
}
@Test
public void test5() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Config17.class);
System.out.println("容器加载完成");
String[] name = app.getBeanDefinitionNames();
for (String s : name) {
System.out.println("容器器中的beanId--->:" + s);
}
StudentServiceFactory studentServiceFactory = app.getBean(StudentServiceFactory.class);
StudengService studengService = studentServiceFactory.createStudentServiceImpl();
studengService.add("zhangsan");
}