Spring的两大特性是IOC和AOP IOC负责将对象动态的注入到容器,从而达到一种须要谁就注入谁,何时须要就何时注入的效果。理解spring的ioc也很重要。 可是今天主要来和你们讲讲aop。 AOP 普遍应用于处理一些具备横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,用于处理系统中分布于各个模块的横切关注点,好比事务管理、日志、缓存等等。java
AOP代理主要分为静态代理和动态代理,spring
AspectJ是静态代理的加强,采用编译时生成 AOP 代理类,所以也称为编译时加强,具备更好的性能。 缺点:但须要使用特定的编译器进行处理数组
Spring AOP使用的动态代理,运行时生成 AOP 代理类,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的所有方法,而且在特定的切点作了加强处理,并回调原对象的方法。 缺点:因为 Spring AOP 须要在每次运行时生成 AOP 代理,所以性能略差一些。缓存
因为aspectj的使用还须要使用特定的编译器进行处理,处理起来有点麻烦。今天重要来说解Spring AOPbash
Spring AOP动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。框架
下面就来用简单的代码来演示下jdk和cglib动态代理的实现原理。maven
/**
* Created by qcl on 2018/11/29
* desc: jdk动态aop代理须要实现的接口
*/
public interface JdkInterface {
public void add();
}
复制代码
/**
* Created by qcl on 2018/11/29
* desc: 被代理的类,即目标类target
*/
public class JdkClass implements JdkInterface {
@Override
public void add() {
System.out.println("目标类的add方法");
}
}
复制代码
-3 ,到了关键的一步,用咱们的MyInvocationHandler,实现InvocationHandler接口,而且实现接口中的invoke方法。仔细看invoke方法,就是在该方法中加入切面逻辑的。目标类方法的执行是由mehod.invoke(target,args)这条语句完成。ide
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Created by qcl on 2018/11/29
* desc:这里加入切面逻辑
*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before-------切面加入逻辑");
Object invoke = method.invoke(target, args);//经过反射执行,目标类的方法
System.out.println("after-------切面加入逻辑");
return invoke;
}
}
复制代码
/**
* Created by qcl on 2018/11/29
* desc:测试
*/
public class JdkTest {
public static void main(String[] args) {
JdkClass jdkClass = new JdkClass();
MyInvocationHandler handler = new MyInvocationHandler(jdkClass);
// Proxy为InvocationHandler实现类动态建立一个符合某一接口的代理实例
//这里的proxyInstance就是咱们目标类的加强代理类
JdkInterface proxyInstance = (JdkInterface) Proxy.newProxyInstance(jdkClass.getClass().getClassLoader(),
jdkClass.getClass()
.getInterfaces(), handler);
proxyInstance.add();
//打印加强过的类类型
System.out.println("=============" + proxyInstance.getClass());
}
}
复制代码
执行上面测试类能够获得以下结果 spring-boot
/**
* Created by qcl on 2018/11/29
* desc:要被代理的类
*/
public class Base {
public void add(){
System.out.println("目标类的add方法");
}
}
复制代码
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Created by qcl on 2018/11/29
* desc:这里加入切面逻辑
*/
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
System.out.println("before-------切面加入逻辑");
methodProxy.invokeSuper(object, args);
System.out.println("after-------切面加入逻辑");
return null;
}
}
复制代码
/**
* Created by qcl on 2018/11/29
* desc:测试类
*/
public class CglibTest {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Base.class);
//回调方法的参数为代理类对象CglibProxy,最后加强目标类调用的是代理类对象CglibProxy中的intercept方法
enhancer.setCallback(proxy);
//此刻,base不是单车的目标类,而是加强过的目标类
Base base = (Base) enhancer.create();
base.add();
Class<? extends Base> baseClass = base.getClass();
//查看加强过的类的父类是否是未加强的Base类
System.out.println("加强过的类的父类:"+baseClass.getSuperclass().getName());
System.out.println("============打印加强过的类的全部方法==============");
FanSheUtils.printMethods(baseClass);
//没有被加强过的base类
Base base2 = new Base();
System.out.println("未加强过的类的父类:"+base2.getClass().getSuperclass().getName());
System.out.println("=============打印增未强过的目标类的方法===============");
FanSheUtils.printMethods(base2.getClass());//打印没有加强过的类的全部方法
}
}
复制代码
下面是打印结果 工具
public class FanSheUtils {
//打印该类的全部方法
public static void printMethods(Class cl) {
System.out.println();
//得到包含该类全部其余方法的数组
Method[] methods = cl.getDeclaredMethods();
//遍历数组
for (Method method : methods) {
System.out.print(" ");
//得到该方法的修饰符并打印
String modifiers = Modifier.toString(method.getModifiers());
if (modifiers.length() > 0) {
System.out.print(modifiers + " ");
}
//打印方法名
System.out.print(method.getName() + "(");
//得到该方法包含全部参数类型的Class对象的数组
Class[] paramTypes = method.getParameterTypes();
//遍历数组
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) {
System.out.print(",");
}
System.out.print(paramTypes[i].getName());
}
System.out.println(");");
}
}
}
复制代码
注意:上面用到了cglib.jar和asm.jar。在咱们的maven的pom.xml里引入下面类库便可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
复制代码
by年糕妈妈qcl