提到spring aop 我们先回顾一下java的代理,代理刚开始时用来实现代码的增强,主要有动态代理和静态代理。
一、静态代理
原理
看下面一个例子
如果用PersonDaoProxy 来代理PersonDao 不难发现,其虽然这个类的方法的代码功能增强,但是却是用重复代码来实现的。
总结结构:
静态代理模式的缺点:
1、如果一个系统中有100Dao,则创建100个代理对象
2、如果一个dao中有很多方法需要事务,则代理对象的方法中重复代码还是很多
3、由第一点和第二点可以得出:proxy的重用性不强
二、动态代理
spring 中的cglib代理和jdk提供的代理有很多共通之处,先回顾一下jdk的代理。从而了解aop概念。
动态代理模式:
1、产生的代理对象和目标对象实现了共同的接口
jdk动态代理
2、代理对象是目标对象的子类
hibernate: Person person =session.load(Person.class,1L); javassisit
spring:cglib动态代理
jdk的动态代理:
1、因为是用jdk的API做到的
2、代理对象是动态产生的
cglib产生的代理类是目标类的子类
注意事项:
1、拦截器中invoke方法体的内容就是代理对象方法体的内容
2、当客户端执行代理对象.方法时,进入到了拦截器的invoke方法体
3 、拦截器中 invoke 方法的 method 参数是在调用的时候赋值的
代理类实现
package cn.zjy.proxyaop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
public class SalaryInterceptor implements InvocationHandler{
private Object target;
private List<Interceptor> interceptors;//这里把切面接口编程
public SalaryInterceptor(Object target,List<Interceptor> interceptors){
this.target = target;
this.interceptors = interceptors;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.print(interceptors.size());
for(Interceptor interceptor:interceptors){
interceptor.interceptor();
}
method.invoke(this.target, args);
return null;
}
}
客户端调用代理类
package cn.zjy.proxyaop;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class SalaryTest {
@Test
public void test(){
Object target = new SalaryManagerImpl();
Logger logger = new Logger();
Security security = new Security();
Privilege privilege = new Privilege();
List<Interceptor> interceptors = new ArrayList<Interceptor>();
interceptors.add(logger);
interceptors.add(security);
interceptors.add(privilege);
SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors);
SalaryManager salaryManager = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
salaryManager.showSalary();
}
}
结果
Logger
Security
privilege
查看工资
三、AOP的概念
看到上述动态代理,就可以做一个AOP名词的解释了
aop:
1、切面
事务、日志、安全性框架、权限等都是切面
2、通知
切面中的方法就是通知
3、目标类
4、切入点
只有符合切入点,才能让通知和目标方法结合在一起
5、织入:
形成代理对象的方法的过程
接下来Spring 的cglib代理原理共通,不过代理类为目标类的子类实现导入cglib jar包
之后,我们只需要修改代理类实现即可
package cn.zjy.proxyaop;
import java.lang.reflect.Method;
import java.util.List;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class SalaryIntercept implements MethodInterceptor {
private Object target;
private List<Interceptor> interceptors;
public SalaryIntercept(Object target,List<Interceptor> interceptors){
this.target = target;
this.interceptors = interceptors;
}
public Object createProxy()
{
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);
enhancer.setSuperclass(target.getClass());
return enhancer.create();
}
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
for(Interceptor interceptor:interceptors){
interceptor.interceptor();
}
arg1.invoke(this.target, arg2);
return null;
}
}
客户端验证
package cn.zjy.proxyaop;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class SalaryTest {
@Test
public void test(){
Object target = new SalaryManagerImpl();
Logger logger = new Logger();
Security security = new Security();
Privilege privilege = new Privilege();
List<Interceptor> interceptors = new ArrayList<Interceptor>();
interceptors.add(logger);
interceptors.add(security);
interceptors.add(privilege);
// SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors);
// SalaryManager salaryManager = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
// salaryManager.showSalary();
SalaryIntercept inter = new SalaryIntercept(target, interceptors);
SalaryManager salaryManager =(SalaryManager)inter.createProxy();
salaryManager.showSalary();
}
}
输出
Logger
Security
privilege
查看工资