循序渐进AOP 04

来源:互联网 发布:三维全景图制作软件 编辑:程序博客网 时间:2024/06/06 01:07

首先我们准备一下用于演示的代码:以模拟MVC模式的经典架构来解释

pojo层

@Repositorypublic void User{    private String name;}

Dao层接口以及实现类

public interface UserDao{   public void saveUser(User user);} 
@Componentpublic class UserDaoImpl implements UserDao{  @Override   public void saveUser(User user){       System.out.println("保存了一个用户:"+user);}}

Service层接口以及实现类

 public interface Uservice{ public void saveUser(User user;}
@Servicepublic class UserServiceImpl implements UserService{@Autowired private UserDao userDao;public void saveUser(User user){  userDao.saveUser(user);}}

Servlet 层

@Controllerpublic class UserServlet{@Autowiredprivate UserServcie userService;public void saveUser(User user){  userService.saveUser(user);}}

事务类

@Componentpublic class TxManager{ public void begin(){System.out.println("开启了事务");}public void commit(){System.out.println("提交了事务");}}




一、静态代理

  要求代理类和被代理的类有相同的方法,因此我们在创建代理类的时候要和被代理的类实现相同的接口。

 要求将事务处理横向放入service层而且做到神不知鬼不觉

@Service("userService")public class StaitcProxy{//在代理类中添加目标对象,因为要执行目标类中的方法(也就是被代理类中的方法)@Autowired @Qulifier("userServiceImpl")private UserService target;//添加事务代码@Autowiredprivate  TxManager txmanager;@Overridepublic void saveUser(User user){txmanager.begin();target.saveUser(user);txmanager.commit();}}

测试类

pulbic class Mytest{@Testpublic void Test(){ApplicationContext context=ClassPathXmlApplicationContext("applicationContext.xml");User user = context.getBean(User.class);UserServlet userServlet = context.getBean(UserServlet.class);userServlet.saveUser(user);}}

输出的结果是

开启了事务保存了一个用户:user=null;提交了事务
有上述模拟测试可知:静态代理降低了耦合度,但是在如果每一个方法都需要事务,就需要创建很多的代理类,代码复用性大大降低。因此出现了动态代理:首先模拟一下JDK提供的动态代理:

   1首先我们需要创建一个动态的代理类,并创建获取被代理的类对象的方法

public class JDkDynamicProxy{private TxManager txmanager;//构造方法中为事务对象赋值public JDKDynamicProxy(){  txmanager = new TxManager;}//创建代理实例对象的方法
public Object getProxy(final Object target){
//创建一个代理实例对象 参数介绍:1.类加载器为了创建相同功能的类//2.目标类的接口   3.回调参数 代理对象执行任何方法的时候会回调Object proxyObject=Proxy.newProxyInstance(target.getClass().getClassLoader,target.getClass.getInterface,newInvocationHandler(){@Overridepublic Object invoke(Object proxy,Method method,Object[] agrs) throws throwable{txmanager.begin();Object result = method.invoke(target,args);txmanager.commit();return result;}});return proxy;}}

JDK提供的动态代理解决了复用性问题,需要添加事务的时候会自动创建代理类,执行相关的操作。那么新的问题又来了,如果一个类没有接口那么此代理便不能使用。这就引出了CGLib动态代理,这是由Spring框架提供的动态代理,接下来我们来模拟演示一下:

//创建一个动态代理类,声明一个获取代理对象的方法public static Object getProxy(final Object target,final Txmanager txmanager){//创建一个增强器Enhancer enhancer = new Enhancer();//通过增强器设置接口enhance.setInterface(target.getClass().getInterfaces());//通过增强器获取父类enhance.setSuperclass(target.getClass());//设置回调enhance.setCallback(new MethodInterceptor(){@Overridepublic Object interceptor(Object proxy,Method method,Object[] args,MthodProxy arg3){txmanaget.begin();Object result = method.invoke(target,args);txmanager.commit();return result;}});return enhance.create();}
以上通过代理进行横向植入并不能进行对被代理对象方法的过滤,就比如将事务植入service层,service层中所有方法都要被植入事务,但是需求并不可能都要求如此。这时Spring框架中AOP就可以弥补这种缺陷。接下来我们来演示一下:

//创建事务切面类和通知方法@Componentpulic class TxAspect{     //添加事务对象    @Autowired   private TxManager txmanger;        //通知方法 我们用环绕通知,这样可以控制目标类方法的执行。public void around(ProceedingJoinPoint joinPoint){txmanager.begin();//执行目标中的方法txmanager.proceed();txmanager.commit();}}
Spring核心配置文件:

<!--配置AOP--><aop:config>       <!--配置切入点-->        <aop:ponitcut expression="within(cn.tedu.sevice.*) id="pc"/>         <!--配置切面-->         <aop:aspect ref="txAspect">                 <!--通知方法-->                 <aop:around method="around" pointcut-ref="pc"/>         </aop:aspect</aop:config>