Spring的Aop(Aspect-Oriented Programming)面向方面编程,其基本原理主要是代理模式的机制,“代理模式” 使用代理对象完成用户请求,屏蔽用户对真实对象的访问,对目标类进行功能增强,在某个方法的执行前后增加一些操作。通俗的说就是,比如校长需要向所有学生传达一个信息,校长会通过班主任老师告诉学生,而校长和学生之间没有存在沟通。老师就起到一个代理的作用。
代理方式:静态代理;动态代理 (基于JDK的动态代理;基于Cglib的动态代理),如下所示:
1.静态代理
静态代理,个人理解可以用 “同一接口,代理注入”来概括,一组代理实现,代理类和目标实现类需要实现同一接口,代理类必须注入目标实现类中,具体可查看如下示例:
public interface IAopPory {
public void testAop();
}
public class A implements IAopPory {
@Override
public void testAop() {
System.out.println("代理实现");
}
}
public class B implements IAopPory {
private A a;
public B(A a) {
this.a = a;
}
@Override
public void testAop() {
System.out.println("调用之前执行。。。可以写自己的方法");
a.testAop();
System.out.println("调用之后执行。。。写自己的处理方法");
}
}
/**
* 静态代理方式
* A和B实现同一接口,B中注入A的实例,在重写testAop方法时,调用A的testAop方法,同时可在B类的*
* testAop方法中扩展自己所需的内容
* */
public class Test {
public static void main(String[] args) {
A a = new A();
B bb = new B(a);
bb.testAop();
}
}
静态代理存在的问题:
(1)通过上面的示例可以看出,代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多,不利于管理,且容易造成代码混乱
(2)实现同一个接口,接口增删方法,目标对象与代理对象都要维护.
2.基于jdk的动态代理
实现步骤:
(1)目标对象必须实现接口(可以多个)
(2)调用实现 Proxy.newProxyInstance(目标对象的classloader,目标对象的实现接口, new InvocationHandler(){});
(3)invoke()的重写
public interface IPory {
public void add();
}
public interface InterfaceAop {
public void delete();
}
public class A implements IPory ,InterfaceAop {
@Override
public void add() {
System.out.println("添加成功");
}
@Override
public void delete() {
System.out.println("删除成功");
}
}
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getName().equals("add")){
System.out.println("判断方法啊等等--"+method.getName());
}
if(method.getName().equals("delete")){
System.out.println("判断方法啊等等--"+method.getName());
}
System.out.println("动态代理执行方法之前"+method.getName());
Object returnValue = method.invoke(target, args);
System.out.println("动态代理执行方法之后"+method.getName());
return returnValue;
}
});
}
public static void main(String[] args) {
ProxyFactory pf = new ProxyFactory(new A());
IPory aa = (IPory) pf.getProxyInstance();
InterfaceAop aa2 = (InterfaceAop) pf.getProxyInstance();
aa.add();
//强转目标对象A,报错类型转换异常
A a = (A) pf.getProxyInstance();
}
}
jdk动态代理不足:
JDK 的动态代理机制是单一代理机制的,它只能代理被代理类的接口集合中的方法,如上示例,getProxyInstance() 生成后的代理类的实例是无法强转为A类型的,只能转成接口之一,这说明其代理的方式是单一的,在任何一种情况下,只能使用某一个接口的功能,而无法同时使用多接口功能。
3.基于Cglib的动态代理
Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型
public class CglibDAO {
public void update(){
System.out.println("cglib -- update");
}
}
/**
* cglib 方式创建代理模式 -子类代理
*
* */
public class CglibProxyFactory implements MethodInterceptor{
private Object cgDao;
public CglibProxyFactory(Object cgDao) {
this.cgDao = cgDao;
}
public Object getProxyInstance(){
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(cgDao.getClass());
//设置回调函数
en.setCallback(this);
//创建子类
return en.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("开始。。。。");
Object returnValue = arg1.invoke(cgDao, arg2);
System.out.println("结束。。。。");
return returnValue;
}
}
/**
* 1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3.动态代理也叫做:JDK代理,接口代理
* */
public class Test {
public static void main(String[] args) {
CglibDAO c = (CglibDAO) new CglibProxyFactory(new CglibDAO())
.getProxyInstance();
c.update();
}
}