设计模式(四) 手动实现AOP代理

1.事务的使用:

      每次对数据库操作我们都需要开启事务,事务开启后,我们就需要对数据库进行一次或者多次操作,当操作完成后就需要提交事务。比如一个业务中多次操作数据库,但是当某个方法出错的时候,我们需要整体回滚,

所以我们把业务的操作绑定在一个事务中。)


 2.手动实现aop管理事务

      我们都知道,如果在业务流程代码中增加事务的开启与提交操作,那么我们在一个类中维护的将会是业务与事务的代码。代码少还可以,但是如果代码量很大,维护起来将显得臃肿复杂。那么我们能不能将业务与事务的代码剥离开来,分开进行维护呢?

    答案肯定是可行的。下面我们通过手动实现AOP代理。    

        AOP     面向切面的编程:

                AOP可以实现“业务代码”与“关注点代码”分离,关注点代码可以想象为事务的那部分代码。

代码示例:

 

IUserDao 接口对象
package com.murong.aop;

//接口
public interface IUserDao
{
    void save();
}

UserDao  目标对象

package com.murong.aop;

import org.springframework.stereotype.Component;

/**
 * 目标对象
 */
@Component // 加入IOC容器
public class UserDao implements IUserDao
{
    @Override
    public void save()
    {
        System.out.println("-----核心业务:保存!!!------");
    }
}

Aop  关注点代码类

 

package com.murong.aop;

import org.springframework.stereotype.Component;

/**
 * 关注点代码类
 */
@Component // 加入IOC容器
public class Aop
{
    // 重复执行的代码
    public void begin()
    {
        System.out.println("事务开启");
    }

    // 重复执行的代码
    public void end()
    {
        System.out.println("事务结束");
    }
}
ProxyFactory  代理工厂
package com.murong.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理工厂 *
 */
public class ProxyFactory
{
    public static Object newProxyInstance(final Object target,final Aop aop)
    {
        // 生成代理对象的方法
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler()
                {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
                    {
                        aop.begin();// 关注点代码
                        Object result = method.invoke(target, args);// 执行目标对象的方法
                        aop.end();// 关注点代码
                        return result;
                    }
                });
    }
}

applicationContext  spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd"
       default-autowire="byType">

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.murong.aop"></context:component-scan>
    <!-- 调用工厂方法,返回UserDao的代理对象 -->
    <bean id="userDao_proxy" class="com.murong.aop.ProxyFactory" factory-method="newProxyInstance">
        <constructor-arg index="0" type="java.lang.Object" ref="userDao"></constructor-arg>
        <constructor-arg index="1" type="com.murong.aop.Aop" ref="aop"></constructor-arg>
    </bean>
</beans>

App  测试类

package com.murong.aop;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App
{
    private ApplicationContext ac = new ClassPathXmlApplicationContext("com/murong/aop/applicationContext");
    @Test
    public void test()
    {
        IUserDao dao = (IUserDao) ac.getBean("userDao_proxy");
        dao.save();
    }
}

结果:

 

  

分析总结:

          关注点代码,就是指重复执行的代码。

业务代码与关注点代码分离,好处?

              -à 关注点代码写一次即可;

          -à开发者只需要关注核心业务;

          -à运行时期,执行核心业务代码时候动态植入关注点代码; 【代理】

 

posted @ 2017-02-19 17:28  晴空~万里  阅读(1734)  评论(0编辑  收藏  举报