1 AOP介绍
- AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术;
- AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型;
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率;
- AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码;
- 经典应用:事务管理、性能监视、安全检查、缓存 、日志等;
- Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码;
- AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
1.1 AOP 实现原理:代理机制
- 接口 + 实现类 : Spring 采用 jdk 的动态代理 Proxy;
- 实现类: 采用
cglib字节码
增强;
1.2 AOP 术语
target
:目标类,需要被代理的类。例如:UserServiceJoinpoint(连接点)
:所谓连接点是指那些可能被拦截到的方法。PointCut 切入点
:已经被增强的连接点。例如:addUser()advice 通知/增强
,增强代码。例如:after、beforeWeaving(织入)
:是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程;proxy 代理类
Aspect(切面)
: 是切入点pointcut和通知advice的结合;
- 一个线是一个特殊的面,一个切入点和一个通知,组成成一个特殊的面。
2 手动代理, 通过 JDK Proxy 类
IUserService
package com.tzb.service;
import com.tzb.model.User;
public interface IUserService {
public void add();
public void add(User user);
// 切面编程
public void addUser();
public void updateUser();
public void delete();
}
UserServiceImpl
package com.tzb.service;
import com.tzb.dao.IUserDao;
import com.tzb.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("myUserService")
public class UserServiceImpl implements IUserService {
@Autowired // spring 会自动往 userDao 赋值,不需要 get/set
private IUserDao userDao;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void add() {
System.out.println("service 创建用户:" + name);
}
@Override
public void add(User user) {
System.out.println("service 添加用户:"+ user);
// 调用 dao
userDao.add(user);
}
@Override
public void addUser() {
System.out.println("添加用户。。。");
}
@Override
public void updateUser() {
System.out.println("更新用户。。。");
}
@Override
public void delete() {
System.out.println("删除用户。。。");
}
public UserServiceImpl() {
System.out.println("UserServiceImpl 被调用");
}
}
- 切面类
MyAspect
package com.tzb.service;
/**
* 切面类,增强代码与切入点的集合
*/
public class MyAspect {
public void before() {
System.out.println("开启事务");
}
public void after() {
System.out.println("提交事务");
}
}
MyBeanFactory
package com.tzb.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyBeanFactory {
public static IUserService createUserService() {
// 1. 创建目标对象 target
final IUserService userService = new UserServiceImpl();
// 2. 声明切面类对象
final MyAspect aspect = new MyAspect();
// 3. 把切面类2个方法,应用到目标类
// 创建代理
IUserService serviceProxy = (IUserService) Proxy.newProxyInstance(
MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 开启事务
aspect.before();
// 内部类访问外部成员变量,userService 加 final
Object retObj = method.invoke(userService, args);
System.out.println("拦截返回值:" + retObj);
// 提交事务
aspect.after();
// 返回值是业务方法的返回值
return retObj;
}
}
);
return serviceProxy;
}
}
- 测试
@Test
public void test1() {
// 自己实现 AOP 编程,使用 JDK 代理来实现
IUserService userService = MyBeanFactory.createUserService();
userService.delete();
userService.addUser();
userService.updateUser();
}
3 cglib 增强字节码
- 没有接口,只有实现类。
- 采用字节码增强框架 cglib,在运行时创建目标类的子类,从而对目标类进行增强。
StuService
package com.tzb.service;
public class StuService {
public void delete() {
System.out.println("删除学生信息");
}
public void update() {
System.out.println("更新学生信息");
}
public void add() {
System.out.println("添加学生信息");
}
}
MyBeanFactory
package com.tzb.service;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyBeanFactory {
/**
* cglib 实现代理
*/
public static StuService createStuService() {
// 1. 创建目标对象 target
final StuService stuService = new StuService();
// 2. 声明切面类对象
final MyAspect aspect = new MyAspect();
// 3. 创建增强对象
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(stuService.getClass());
// 设置回调【拦截】
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// proxy 代理对象是 StuService 的子类
//System.out.println(methodProxy);
aspect.before();
// 放行方法
//Object retObj = method.invoke(stuService, args);
Object retObj = methodProxy.invokeSuper(proxy, args);
System.out.println("拦截...");
aspect.after();
return retObj;
}
});
// 创建代理对象
StuService serviceProxy = (StuService) enhancer.create();
// System.out.println("代理对象:" + serviceProxy);
return serviceProxy;
}
}
- 测试
@Test
public void test1() {
// 实现 AOP 编程,使用 cglib 代理来实现
StuService ss = MyBeanFactory.createStuService();
ss.add();
ss.update();
ss.delete();
}