什么是AOP
AOP是面向切面编程,是一种编程思想。
为什么要有AOP
目的是用于实现关注点代码和业务代码的分离解耦,从而提高关注点代码的可维护性和可扩展性
AOP专业术语:
aspect:切面
advice:通知 - 切面类中的方法
joinPoint:连接点 - 业务类里面所有的方法(预备役)
pointCut: 切点 - 关注点代码切入的连接点叫做切点
weaving:织入 - 关注点代码织入业务代码
AOP通知类型:
前置通知: @Before
后置通知: @After
环绕通知: @Around
返回后通知: @AfterReturing
抛出异常后通知: @AfterThrowing
AOP底层原理- 动态代理机制
运行期通过代理机制将关注点代码植入到业务代码中,产生的新对象叫做代理对象,运行期执行的是代理对象中融合之后的方法代码
动态代理机制分类:
JDK动态代理:为实现类接口的目标对象生成代理对象
CGLIB动态代理:为没有实现接口的目标对象生成代理对象
JDK动态代理
适用于实现了接口的目标对象,为其生成代理对象,底层代码示例
生成代理对象需要什么分析:
------1. 创建一个实现了接口的目标对象
package ;
public interface UserOperation {
void login(String userName,String pwd);
}
------//实现接口
package ;
public class UserOperationImpl implements UserOperation {
@Override
public void login(String userName, String pwd) {
System.out.println("开始登陆!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("登陆成功!");
}
}
------2. 创建切面类对象,保存增强/关注点代码
- 实现InvocationHandler接口
package ;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
public class TimeAspect implements InvocationHandler {
private Object target;//目标对象 这里面包含我要拦截的方法
public TimeAspect(Object target){
this.target = target;
}
//重写方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long t1 = System.currentTimeMillis();//当前时间的毫秒
Object returnVal = method.invoke(target,args);//参数 目标对象里面的方法
long t2 = System.currentTimeMillis();//当前事件
System.out.println("耗时:"+(t2-t1)+"ms");
return returnVal;//原来方法返回什么 代理对象返回什么
}
}
-----3. 使用JDK的动态代理机制生成代理对象
package ;
import java.lang.reflect.Proxy;
public class JDKProxyFctory {
public static void main(String[] args) {
//创建目标对象
UserOperation userOperation = new UserOperationImpl();
//创建增强对象
TimeAspect aspect = new TimeAspect(userOperation);
//使用JDK的api来生成代理对象 返回代理对象Object类型
UserOperation proxy = (UserOperation) Proxy.newProxyInstance(
userOperation.getClass().getClassLoader(),//目标对象的类加载器
userOperation.getClass().getInterfaces(),//目标对象所属类的所有接口类型
aspect);//增强对象
//调用代理对象中的login方法
proxy.login("tom","123");
System.out.println(proxy.getClass());
}
}
-----4. 调用代理对象中的方法,看执行结果是否为融合后的代码
出现$Proxy0就代表成功了
CGLib动态代理
适用于没有实现接口的目标对象,为其生成代理对象 底层代码示例
-----1. 创建一个没有实现接口的目标对象
package ;
public class UserRegist {
public void regist(){
System.out.println("开始注册!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("注册成功!");
}
}
-----2. 创建增强类对象
-实现MethodInterceptor
package ;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//方法拦截接口
public class CglibTimeAspect implements MethodInterceptor {
private Object target;//跟上文JDK同理
public CglibTimeAspect(Object target){
this.target = target;
}
@Override //代理对象,拦截到的方法,拦截的方法的参数列表,方法代理对象
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
long t1 = System.currentTimeMillis();
Object returnVal = method.invoke(target,args);
long t2 = System.currentTimeMillis();
System.out.println("耗时:"+(t2-t1)+"ms");
return returnVal;
}
}
-----3. 使用CGLIB的api方法生成代理对象
import org.springframework.cglib.proxy.Enhancer;
public class CglibProxyFactory {
public static void main(String[] args) {
//创建目标对象
UserRegist userRegist = new UserRegist();
//创建增强对象
CglibTimeAspect aspect = new CglibTimeAspect(userRegist);
//使用cglib的api方法生成代理对象
UserRegist proxy = (UserRegist) Enhancer.create(userRegist.getClass(),aspect);
//通过代理对象调用目标方法
proxy.regist();
System.out.println(proxy.getClass());
}
}
-----4. 调用代理对象中的目标方法,看执行的结果是否为组合后的代码
出现下图就代表成功了
Spring中AOP代理机制的选择
spring的aop会自动根据目标对象是否实现类接口来智能的选择动态代理机制.
若目标对象实现了接口,则选择JDK动态代理机制
若目标对象没有实现接口,则自动选择CGLIB动态代理机制
从SpringBoot2.xx版本开始,不论目标对象是否实现了接口,均会默认选择CGLIB动态代理机制.
AOP应用
1. spring的声明式事务管理
2. 记录日志
3. 性能统计