对于SpringAOP的学习,是一个比较有趣的东西,要充分认识他,你就必须充分认识代理模式,因为Spring里面的AOP基本都是通过jdk的动态代理模式来实现的。
代理模式的精髓就是,你自己要干的事情,你不干了,叫你的代理帮你做了。代理模式分为两种动态代理和静态代理。
回味一下静态代理:所谓的静态代理就是提前就已经存在了,就有点像static一样,不是通过运行的时候才产生的。基本的步骤是这样子的:一个接口两个类。本来是这样的如果在定义一个接口以后,我们有一个类去实现了里面的所有方法,这个时候突然需要加点东西,比如说写日志啊,安全性检查啊这些。这些功能是跟本来的业务没有任何关系的,他们是不相互影响的。那么这个时候你可以选择写一个公共方法,
然后在每个方法的第一句话来调用这个方法,但是这样违背了我们ooad的ocp原则,所以我们要采用代理模式,静态代理的核心是,实现与被代理类相同的接口,因为你要代理谁你并不知道,所以你还必须拥有被代理类的引用。这样你在代理类里面把该做的就做了,以后要用的时候就直接用代理类就可以了。这样没有破坏我们的ocp原则,也实现了我们想要的功能。具体代码如下:
接口类:
package com.lovo.json.bean;
public interface UserManager {
public void add(String name, String password);
public void del(int id);
public String find(int id);
}
实现类:也就是被代理类:
package com.lovo.json.bean;
public class UserManagerImp implements UserManager {
public void add(String name, String password) {
System.out.println("-------add---------");
}
public void del(int id) {
System.out.println("-------del---------");
}
public String find(int id) {
System.out.println("-------find---------");
return null;
}
// private void salf(){
// System.out.println("--------salf------");
// }
}
最后就是代理类:
package com.lovo.json.bean;
public class UserManagerImpProxy implements UserManager {
private UserManager userManager;
public UserManagerImpProxy(UserManager userManager){
this.userManager = userManager;
}
public void add(String name, String password) {
salf();
userManager.add(name, password);
}
public void del(int id) {
salf();
userManager.del(id);
}
public String find(int id) {
//这个方法没有安全性检查,所以在运行的时候不调养salf方法
return userManager.find(id);
}
private void salf(){
System.out.println("--------salf------");
}
}
下面是动态代理:
因为我们发现这个本来跟业务没有多大关系的安全性检查,要是全部类全部方法都要用上的话,那不是要写死人。所以jdk为我们提供了动态代理这个方法,就是为了完成很多方法都需要拥有相同的功能的时候,我们也可以把这种东西叫做模块化。具体步骤是这样的:
接口和实现类没有任何变化。关键是代理类,我们把他抽取成一个对象,这个对象拥有一些公共的方法,也就是把共有的方法模块化了:
package com.lovo.json.module;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SelfHandler implements InvocationHandler {
//拥用代理目标对象的引用
private Object targetObj;
//用对外提供一个返回被代理对象的方法 你才晓得你代理的是哪个
public Object newProxy(Object targetObj){
this.targetObj = targetObj;
return Proxy.newProxyInstance(this.targetObj.getClass().getClassLoader(),//得到类加载器
this.targetObj.getClass().getInterfaces(), //得到该类
的接口
this);//代理类
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
this.salf();
//因为有些方法有返回值而有些没有,所以跟个结果
Object reslut = null;
//方法不做任何判定的情况是默认加到所有方法,所以Spring用了正则表达式来区分哪些方法需要加,哪些不需要
reslut = method.invoke(this.targetObj, args);
return reslut;
}
private void salf(){
System.out.println("---------salf-------");
}
}
这样就完成了所有工作,下面来测试一下:
package com.lovo.json.client;
import com.lovo.json.bean.UserManager;
import com.lovo.json.bean.UserManagerImp;
import com.lovo.json.module.SelfHandler;
import junit.framework.TestCase;
public class TestClient extends TestCase{
public void testProxy(){
//首先必须产生一个代理类
SelfHandler handler = new SelfHandler();
UserManager userManager = (UserManager)handler.newProxy(new UserManagerImp());
userManager.add("ad", "asd");
}
}
测试成功,所有方法都添加了安全性检查这个功能。
从上面的列子可以看出,当Spring实现AOP功能的时候,他还是利用了jdk里面的动态代理方式,下面我们再来看看Spring里面怎么实现AOP的,他有两种实现方法,一种是XML的,一种是注解的,我们通过XML的方式来和上面的动态代理做比较,这样会有更清晰的认识。
首先两个基础类还是没有变化,就是一个接口一个实现类。这里需要变化的只有一点,就是我们的handler也就是功能模块,对于Spring来说他是轻量级的框架,不需要继承他的什么东西,所以handler类就变成了这样:
package com.lovo.json.module;
public class SelfHandler {
private void salf() {
System.out.println("---------salf-------");
}
}
然后我们只需要在xml做如下的配置就可以了
<!-- 肯定要用到两个类的实例所以创建两个类 -->
<bean id="userManager" class="com.lovo.json.bean.UserManagerImp" />
<bean id="selfHandler" class="com.lovo.json.module.SelfHandler" />
<!-- 然后需要用到aop中的配置 aop config -->
<aop:config>
<aop:aspect id="self" ref="selfHandler"><!-- 这里指的是切入点也就是我的handler -->
<!-- 切入点是配出来的 expression_r表达式嘛-->
<aop:pointcut id="allAddMethod" expression_r="execution(* *(..))"/>
<!-- 这里是之前还是之后执行哪个方法,往哪个切入点开始切->
<aop:before method="salf" pointcut-ref="allAddMethod"/>
</aop:aspect>
</aop:config>
</beans>
就总结到这里,上课胡老还讲了个其他的方法,好好温习一下,原理都差不多,over!