AOP的原理就是java的动态代理机制。面向切面编程:为什么叫切面呢?相对于一般的开发模式是线性的,比如从后台的Mapper开始往数据库操作数据,传到Dao层,再到Service层进行数据的处理,最后到前端的展示,这是符合人类做事的特征,一条线。而切面,是一个面咯,比如说对所有add方法进行操作,比如对service层进行操作。
public interface Subject {
public void say();
public void action(String str);
}
~~~~~~~~~~~~
public class SubjectImplment implements Subject{
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("向日葵漂亮");
}
@Override
public void action(String str) {
// TODO Auto-generated method stub
System.out.println(str);
}
}
~~~~~~~~~~~~~~~~~
public class ProxySubject implements InvocationHandler{
private Object obj;
public ProxySubject(Object obj) {
// TODO Auto-generated constructor stub
this.obj = obj;
}
@Override
public Object invoke(Object objI, Method method, Object[] args)
throws Throwable {
// 调用实际的方法前
System.out.println("开始");
method.invoke(obj, args); //注意此处传入的是obj,不是obj1
System.out.println("结束");
return null;
}
}
~~~~~~~~~~~~~~~
public class Client {
public static void main(String[] args) {
//真正调用的对象
//SubjectImplment subImplment = new SubjectImplment();
Subject realsubject = new SubjectImplment(); //注意此处new的是调用实现的方法new出来的
//将对象传入代理类
InvocationHandler handler = new ProxySubject(realsubject);
//利用创建代理对象,代理类的实例
Subject subject = (Subject) Proxy.newProxyInstance(realsubject.getClass().getClassLoader(), realsubject.getClass().getInterfaces(), handler);
subject.say();
subject.action("动态代理");
}
}
~~~~~~~~~~~
开始
向日葵漂亮
结束
开始
动态代理
结束
~~~~~~~~~~~~
每次执行被代理对象(接口的具体实现类)的方法的时候,代理类的方法都会被执行。估计这就是产生日志的方式吧。
spring用代理类包裹切面,把他们织入到Spring管理的bean中。也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成调用伪装类,伪装类中就先执行了切面,再把调用转发给真正的目标bean。
现在可以自己想一想,怎么搞出来这个伪装类,才不会被调用者发现(过JVM的检查,JAVA是强类型检查,哪里都要检查类型)。
1.实现和目标类相同的接口,我也实现和你一样的接口,反正上层都是接口级别的调用,这样我就伪装成了和目标类一样的类(实现了同一接口,咱是兄弟了),也就逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring采用运行时),伪装类(代理类)就变成了接口的真正实现,而他里面包裹了真实的那个目标类,最后实现具体功能的还是目标类,只不过伪装类在之前干了点事情(写日志,安全检查,事物等)。
这就好比,一个人让你办件事,每次这个时候,你弟弟就会先出来,当然他分不出来了,以为是你,你这个弟弟虽然办不了这事,但是他知道你能办,所以就答应下来了,并且收了点礼物(写日志),收完礼物了,给把事给人家办了啊,所以你弟弟又找你这个哥哥来了,最后把这是办了的还是你自己。但是你自己并不知道你弟弟已经收礼物了,你只是专心把这件事情做好。
顺着这个思路想,要是本身这个类就没实现一个接口呢,你怎么伪装我,我就压根没有机会让你搞出这个双胞胎的弟弟,那么就用第2种代理方式,创建一个目标类的子类,生个儿子,让儿子伪装我
2.生成子类调用,这次用子类来做为伪装类,当然这样也能逃过JVM的强类型检查,我继承的吗,当然查不出来了,子类重写了目标类的所有方法,当然在这些重写的方法中,不仅实现了目标类的功能,还在这些功能之前,实现了一些其他的(写日志,安全检查,事物等)。
这次的对比就是,儿子先从爸爸那把本事都学会了,所有人都找儿子办事情,但是儿子每次办和爸爸同样的事之前,都要收点小礼物(写日志),然后才去办真正的事。当然爸爸是不知道儿子这么干的了。这里就有件事情要说,某些本事是爸爸独有的(final的),儿子学不了,学不了就办不了这件事,办不了这个事情,自然就不能收人家礼了。
前一种兄弟模式,spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把对这些接口的任何调用都转发到目标类。
后一种父子模式,spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知,并且把对这个子类的调用委托到目标类。
相比之下,还是兄弟模式好些,他能更好的实现松耦合,尤其在今天都高喊着面向接口编程的情况下,父子模式只是在没有实现接口的时候,也能织入通知,应当做一种例外。
***********************************************
Aop在spring中的配置实践:
Subject和SubjectImplment的代码不变。新增一个LogAdvice来模拟日志的添加
public class LogAdvice {
public void beforeLog() {
System.out.println("开始执行");
}
public void afterLog() {
System.out.println("结束执行");
}
}
~~~~~~~~~~~~~~~
application.xml的配置
<!-- ~~~~~~~~~~~ -->
<!-- 目标对象 -->
<bean id="subjectImplment" class="com.enjoyor.soa.traffic.server.tms.controller.SubjectImplment"/>
<!-- 通知 -->
<bean id="logAdvice" class="com.enjoyor.soa.traffic.server.tms.controller.LogAdvice"/>
<aop:config>
<aop:aspect id="logAspect" ref="logAdvice">
<!-- 切入点 -->
<aop:pointcut id="beforePointCut"
expression="execution(* say*(..))"/>
<aop:pointcut id="afterPointCut"
expression="execution(* say*(..))"/>
<!-- 织入(通知作用于切入点) -->
<aop:before method="beforeLog" pointcut-ref="beforePointCut"/>
<aop:after method="afterLog" pointcut-ref="afterPointCut"/>
</aop:aspect>
</aop:config>
<!-- ~~~~~~~~~~~~~~~~ -->
~~~~~~~~~~~
import org.springframework.context.ApplicationContext;//注意包类型
import org.springframework.context.support.ClassPathXmlApplicationContext;//注意包类型
public class TestJava{
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");//import适当的jar包非常重要
Subject subject = (Subject) context.getBean("subjectImplment");
subject.say();
}
}
~~~~~~~~~~~
开始执行
向日葵漂亮
结束执行
~~~~~~~~~~~~
参考:http://blog.csdn.net/qukaiwei/article/details/50367761
浙公网安备 33010602011771号