AOP(面向切面编程)是OOP的延申。
在处理业务的过程中,通过调用对象的方法可以完成对业务的处理;但是如果在业务处理之前要进行一些非核心的处理,如输出日志或做空值判断,这些非核心代码并不重要,并且是可以重用的,我们不想把它加入到核心代码中,但是在执行核心代码之前又必须要进行非核心的处理,这个时候我们就要用到AOP,其核心思想就是代理。
AOP用到的设计模式就是代理模式,即在不影响原功能的前提下,拓展新的功能。
代理分静态代理和动态代理
静态代理
public interface IUserDao {
public void add();
}
@Component //相当于生成了userDao的bean
public class UserDaoImpl implements IUserDao {
@Override
public void add() {
System.out.println("userDao add...");
}
}
public class Proxy implements IUserService{
private IUserService userService;
public Proxy(IUserService userService) {
this.userService = userService;
}
@Override
public void add() {
before();
userService.add();
after();
}
void before(){
//do sth
}
void after(){
//dosth
}
}
这就是静态代理,很简单,只需要创建一个代理类也去继承相同的接口,重写对应的方法,并在构造函数里面初始化被代理类的对象,在调用核心代码之前,就可以执行其他的非核心代码,并且不影响原功能。
静态代理的缺点:需要再创建一个类去继承接口,增强代码在编译期就会被织入,并且接口变动或实现类变动时,代码变动较大。
动态代理
JDK动态代理:
public class MyMainApp {
public static void main(String[] args) {
//静态代理
// MyProxy myProxy = new MyProxy();
//myProxy.add();
//动态代理
IUserDao userA = new UserA();
IUserDao proxyInstance = (IUserDao) Proxy.newProxyInstance(UserA.class.getClassLoader(), UserA.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("add")){
System.out.println("before...");
method.invoke(userA, args);
}
return null;
}
});
proxyInstance.add();
}
}
这里用到了java.lang.reflect包里的Proxy类,可以看到JDK动态代理要获取到代理对象需要传入3个参数:
1.被代理类的类加载器
2.被代理类的接口
3.InvocationHandler的实现类
所以,如果被代理类没有接口,那么就不能用JDK动态代理,需要用CGLib动态代理。
CGLib动态代理:
class MyCGLibProxy implements MethodInterceptor{
private IUserDao userDao;
public MyCGLibProxy(IUserDao userDao) {
this.userDao = userDao;
}
public IUserDao getProxy(){
//CGLib动态代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(IUserDao.class);
enhancer.setCallback(this);
return (IUserDao) enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before...");
method.invoke(userDao, args);
return null;
}
}
CGLib需要使用Enhancer类来创建代理对象,创建代理时需要传入被代理对象的父类(所有类都有一个公共的父类Object)。
AOP同时采用JDK和CGLib两种代理方式,默认JDK动态代理方式。
@Component
@Aspect //切面类
public class MyAspect {
//设置前置增强 * 包名+类名+方法名+(..)
@Before("execution(* com.zq.service.impl.*.*(..))")
public void before(){
System.out.println("before....");
}
//设置后置增强
@After("execution(* com.zq.service.impl.*.*(..))")
public void after(){
System.out.println("after....");
}
}
SpringAOP使用场景:如计算程序执行时间,输出日志等。