SpringAOP原理
1. 代理模式(Proxy Pattern)
其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。
代理分为两种方式: 静态代理与动态代理
静态代理是在程序运行之前就确立了代理关系; 而动态代理则是运行时才确立代理关系.
举个例子: 对于普通人来说, 有官司来了才会去找律师; 而对于企业来说, 企业内会有一个法律顾问, 官司来了法律顾问上. 前者相当于动态代理, 后者就相当于静态代理.
1.1 静态代理
先来看看关系图:
业务接口ISomeService
中的方法是: 需要被增强的方法
目标类SomeServiceImpl
是: 代理类要增强的类,实现ISomeService
接口
代理类SomeServiceProxy
实现了ISomeService
接口,主要有两个任务:
- 调用目标类的目标方法
- 增强目标方法
下面看代码:
步骤 1
创建一个接口
package Proxy_Pattern;
public interface ISomeService {
public void doService1();
public void doService2();
}
步骤 2
创建实现接口的实体类
- 目标类
package Proxy_Pattern;
public class SomeServiceImpl implements ISomeService {
@Override
public void doService1() {
System.out.println("This is service 1");
}
@Override
public void doService2() {
System.out.println("This is service 2");
}
}
- 代理类
package Proxy_Pattern;
public class SomeServiceProxy implements ISomeService {
ISomeService target;
//传入目标类
public SomeServiceProxy(ISomeService target){
this.target = target;
}
@Override
public void doService1() {
//增强方法
System.out.println("hello everyone");
//目标类的方法
target.doService1();
}
@Override
public void doService2() {
//增强方法
System.out.println("good morning");
//目标类的方法
target.doService2();
}
}
步骤 3
当被请求时,使用 SomeServiceProxy
来获取 SomeServiceImpl
类的对象。
package Proxy_Pattern;
public class Test {
public static void main(String[] args) {
ISomeService target = new SomeServiceImpl();
ISomeService proxy = new SomeServiceProxy(target);
proxy.doService1();
System.out.println("================");
proxy.doService2();
}
}
步骤 4
执行程序,输出结果:
hello everyone
This is service 1
================
good morning
This is service 2
1.2 动态代理
动态代理又分为两种,一中是JDK动态代理, 一种是CGLIB动态代理
1.2.1 JDK动态代理
JDK动态代理要求, 目标类与代理类要实现同一接口
无需创建代理类, 可以通过Proxy包下的newProxyInstance
方法返回一个代理类的实例(动态代理对象)
先来看关系图:
步骤1
创建一个接口
package JDKDynamicProxy;
public interface ISomeService {
public void doService1();
public void doService2();
}
步骤2
创建接口的实现类
package JDKDynamicProxy;
public class SomeServiceImpl implements ISomeService {
@Override
public void doService1() {
System.out.println("This is service1");
}
@Override
public void doService2() {
System.out.println("This is service2");
}
}
步骤3
创建调用处理器
package JDKDynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ServiceHandler implements InvocationHandler {
Object target;
//传入目标类对象
public ServiceHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强逻辑,如果不进行判断,会增强所有的方法
System.out.println("执行" + method.getName() +"方法");
//调用目标方法
method.invoke(target, args);
return null;
}
}
步骤 4
当被请求时,使用 Proxy.newInstance()
返回一个代理类实例,来获取 SomeServiceImpl
类的对象。
package JDKDynamicProxy;
import Proxy_Pattern.ISomeService;
import Proxy_Pattern.SomeServiceImpl;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
//目标类
ISomeService target = new SomeServiceImpl();
//方法处理器
ServiceHandler handler = new ServiceHandler(target);
//返回一个代理类实例
ISomeService proxy = (ISomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
proxy.doService1();
System.out.println("==================");
proxy.doService2();
}
}
其中newProxyInstance
方法:
newProxyInstance(ClassLoader loader,//一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
Class<?>[] interfaces,//一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口
InvocationHandler h//一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
)
步骤 5
执行程序,输出结果:
执行doService1方法
This is service 1
==================
执行doService2方法
This is service 2
1.2.2 CGLIB动态代理
CGLIB动态代理, 目标类没有生成接口, 要生成代理对象.
原理:通过子类进行增强(子类增强父类)
先来看关系图:
步骤1
创建目标类
package CglibProxy;
public class SomeService{
public void doService1() {
System.out.println("This is service1");
}
public void doService2() {
System.out.println("This is service2");
}
}
步骤2
创建调用处理器
package CglibProxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class Proxy implements MethodInterceptor {
Object target;
public Proxy(Object target){
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//增强逻辑
System.out.println("执行" + method.getName() +"方法");
//目标对象方法的调用
method.invoke(target, objects);
return null;
}
public static Object getProxy(Object target){
Enhancer enhancer = new Enhancer();
// 设置需要代理的对象, 设置为父类
enhancer.setSuperclass(target.getClass());
// 设置代理人
enhancer.setCallback(new Proxy(target));
// 返回代理类的实例
return enhancer.create();
}
}
当代理对象的方法被调用时,就会执行intercept
方法,
步骤3
当被请求时,使用 getProxy()
方法来获得代理类实例,利用代理对象获取 SomeService
类的对象。
package CglibProxy;
public class Test {
public static void main(String[] args) {
SomeService target = new SomeService();
SomeService proxy = (SomeService) Proxy.getProxy(target);
proxy.doService1();
System.out.println("=============");
proxy.doService2();
}
}
步骤4
输入结果
执行doService1方法
This is service1
=============
执行doService2方法
This is service2
1.2.3 两种动态代理的区别
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理(对接口也可以实现),主要是对指定的类生成一个子类,覆盖其中的方法(继承)
2. SpringAOP
AOP思想的实现一般都是基于 代理模式 ,在JAVA中一般采用JDK动态代理模式,但是我们都知道,JDK动态代理模式只能代理接口而不能代理类。因此,Spring AOP 会这样子来进行切换,因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理。
- 如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
- 如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。