springAOP面向切面编程
AOP中文手册没法看,概念比佛法还深还抽象!我们进入例子理解
前提铺垫:动态代理模式
Spring容器的启动流程
1)容器创建容器中的对象
2)进入装配阶段
3)调用init()方法
4)getBean得到对象调用方法
5)容器关闭调用destroy
静态代理模式
public class PersonProxy implements PersonDao{ private Person dao;public void savePerson(){
private Transaction tran;
public Personproxy(Person dao,Transaction tran){
this.dao=dao;
this.tran=tran;
}
@Override
}
看起来好香很像装饰模式哦。
首先PersonDao是一个接口定义了savePerson();实际使用的时候我们给他开事物非常麻烦,于是我是用一个代理类来得到他的代理
然后重写的时候添加事物。总结一下:
1静态代理没有做到代码的重用,无法切面编程。如果接口定义了xxx()那么你得事务还得在xxx()中体现
2如果你的service层中有一百个类,难道用静态代理写100个代理类?接口中国100个方法你就要在代理中写100个?
那还不如直接在接口中写事务算了,何必重新写代理。
3因为代理类也继承了被代理类的接口,一旦接口发生改变那么代理类的改变也不堪设想。
因此静态代理类无法解决复杂的问题以及不可能处理面向切面编程。
那么我想需要使用代理解决什么问题呢?
用一个代理类实现所有dao层或者service层的方法的事物的开启和提交,一次编写,横切一个层。只能使用动态代理
JDK动态代理
动态代理分为JDK的方式和Cglib的方式
企业里就算不用spring的AOP也不会用JDK的Proxy
1、在拦截器中只能处理目标对象的目标方法功能单一。如果累加就会臃肿。本例只能处理事物
2、有20个service每个类有20个方法,百分之50需要开启事物,200个方法需要事物
200个方法的方法名都不一样,你得代理如何判断方法呢?(可以用打注解来解决)
但是也要打200个注解,也还是麻烦。
所以拦截器中的invoke方法的if判断在真实开发环境下是不靠谱的。因为方法很多。打注解不是完美解决方法
public class MyHandler implements InvocationHandler{
private Object target;//目标类
private Transaction transaction;
public MyHandler(Object target, Transaction transaction) {
super();
this.target = target;
this.transaction = transaction;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
String metnodname=method.getName();
if("savePerson".equals(metnodname)||"updatePerson".equals(metnodname)){
this.transaction.beginTransaction();
method.invoke(target, args);
this.transaction.commit();
}else{
method.invoke(target, args);
}
return null;
}
}
/**
* 1、invoke方法什么时候执行
* 当调用代理对象的方法的时候,进入自己定义的handler的invoke
* 2、代理对象的方法体的内容是什么
* invoke方法中的内容就是代理对象的方法内容
* 拦截器中的invoke方法中的参数method是谁在什么时候传递过来的?
* 代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke方法中的参数method就是
* 代理对象调用的方法
* @param args
*/
public static void main(String[] args) {
Object target=new PersonDaoImpl();
Transaction t=new Transaction();
MyHandler interceptor = new MyHandler(target, t);
PersonDao proxy= (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),interceptor);
proxy.savePerson();
proxy.updatePerson();
}
}
自定义拦截器(其实就是把功能抽象理解为拦截器的功能,把这些功能放入一个自定义叫做拦截器的类中),把事物啊 日志啊等等需要在代理中添加的功能都放入拦截器中,这样就可以在代理对象的方法调用的时候将拦截器全部执行。只是理解为拦截器,其实就是一个功能集合(参考代码)
Cglib代理(重中之重)
Cglib在spring中帮我们提供了
Cglib-nodep-2.1.3.jar导入工程
通过他产生的代理对象是目标类的子类
就是说代理类不必和被代理类实现同一个接口,因为代理类就是被代理类的孩子
public class MyInterceptor implements MethodInterceptor{
private Object target;//目标类
private Transaction transaction;
public MyInterceptor(Object target, Transaction transaction) {
super();
this.target = target;
this.transaction = transaction;
}
public Object createProxy(){
//代码增强类
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);//参数为拦截器(设置回调者)
enhancer.setSuperclass(target.getClass());//生成的代理类的父类是目标类
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
this.transaction.beginTransaction();
method.invoke(target);
this.transaction.commit();
return null;
}
}
============================
public class Client {
@Test
public void testCGlib(){
Object target = new PersonDaoImpl();
Transaction transaction = new Transaction();
MyInterceptor interceptor = new MyInterceptor(target, transaction);
PersonDaoImpl personDaoImpl = (PersonDaoImpl)interceptor.createProxy();
personDaoImpl.savePerson();
}
}
AOP的各个概念
spring中已经帮我们做好了AOP,只需要了解概念即可。
之前我们看的Transactioin类就是一个切面
暂时可以理解为修饰service层功能的类就是切面,切面的方法就是通知
public clss Transaction{ //切面
public void beginTransaction(){
。。。。。。。
}
public void commit(){ //通知
..................
}
}
personDao.updatePerson()
客户端调用哪个方法,那个方法就是连接点
之前的invoke方法中的判断代码:
if("savePerson".equals(metnodname)||"updatePerson".equals(metnodname)){
this.transaction.beginTransaction();
method.invoke(target, args);
this.transaction.commit();
}else{
method.invoke(target, args);
}
整个判断的过程就是切入点(相当于条件)
整个形成代理对象的方法过程就称为织入。
excution表达式图---
----
----
---
好好研究下表达式的写法。
原理:
通知的分类-------------------------------------------