面向切面编程aop

面向切面编程 (AOP)

Aspect Oriented Programming

可以通过预编译和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

主要功能

日志记录,性能统计,安全控制,事务处理,异常处理等等

主要意图

将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

案例-事务管理


注解方式,定义事务开关标记

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Tran {
}


需要开启事务的方法上写上自定义的注解

public interface UserService  extends Service{
/**
 * 注册用户
 * @param user 封装了用户数据的userbean
 */
@Tran
void regist(User user);
}

service实现类

public class UserServiceImpl implements UserService {
    private UserDao dao = BasicFactory.getFactory().getDao(UserDao.class);
    public void regist(User user) {
    try{
        //1.校验用户名是否已经存在
        if(dao.findUserByName(user.getUsername())!=null){
            throw new RuntimeException("用户名已经存在!!");
        }
        //2.调用dao中的方法添加用户到数据库
        user.setRole("user");
        user.setState(0);
        user.setActivecode(UUID.randomUUID().toString());
        dao.addUser(user);
        //3.发送激活邮件
        Properties prop = new Properties();
        prop.setProperty("mail.transport.protocol", "smtp");
        prop.setProperty("mail.smtp.host", "localhost");
        prop.setProperty("mail.smtp.auth", "true");
        prop.setProperty("mail.debug", "true");
        Session session = Session.getInstance(prop);
        Message msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress("[email protected]"));
        msg.setRecipient(RecipientType.TO, new InternetAddress(user.getEmail()));
        msg.setSubject(user.getUsername()+",来自estore的激活邮件");
        msg.setText(user.getUsername()+",点击如下连接激活账户,如果不能点击请复制到浏览器地址栏访问:http://www.estore.com/ActiveServlet?activecode="+user.getActivecode());
        Transport trans = session.getTransport();
        trans.connect("aa", "123");
        trans.sendMessage(msg, msg.getAllRecipients());
    }catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
        }
    }
}

事务管理工具类,改造数据源,判断是否开启事务

public class TransactionManager {
    private TransactionManager() {
    }
    //--数据源,整个程序中都只有这一个数据源
    private static DataSource source = new ComboPooledDataSource();
    //--是否开启事务的标记
    private static ThreadLocal<Boolean> isTran_local = new ThreadLocal<Boolean>(){
    @Override
    protected Boolean initialValue() {
        return false;//--最开始false,表明默认不开启事务
    }
    };
    //--保存真实连接的代理连接,改造过close方法
    private static ThreadLocal<Connection> proxyConn_local = new ThreadLocal<Connection>(){};
    //--保存真实连接
    private static ThreadLocal<Connection> realconn_local = new ThreadLocal<Connection>(){};
    /**
     * 开启事务的方法
     */
    public static void startTran() throws SQLException{
    isTran_local.set(true);//--设置事务标记为true
    final Connection conn = source.getConnection();//--创建连接,所有当前线程中的数据库操作都基于这个conn
    conn.setAutoCommit(false);//--开启事务
    realconn_local.set(conn);//--为了方便后续关闭连接,将这个连接保存起在当前线程中
    //--由于一个事务需要执行多条sql,每个sql执行过后都关闭连接,这样一来后续的sql没法执行,所以这个地方法改造close方法,使他不能关闭连接
    Connection proxyConn = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces()
    , new InvocationHandler(){
    public Object invoke(Object proxy, Method method,
    Object[] args) throws Throwable {
    if("close".equals(method.getName())){
        return null;
    }else{
        return method.invoke(conn, args);
    }
    }
    });
    proxyConn_local.set(proxyConn);
    }
    /**
     * 提交事务
     */
    public static void commit(){
        DbUtils.commitAndCloseQuietly(proxyConn_local.get());
    }
    /**
     * 回滚事务
     */
    public static void rollback(){
        DbUtils.rollbackAndCloseQuietly(proxyConn_local.get());
    }
    /**
     * 这个方法应该做到:
     * 如果没有开启过事务,则返回最普通的数据源
     * 如果开启过事务,则返回一个改造过getConnection方法的数据源,这个方法改造后每次都返回同一个开启过事务的Connection
     * @return
     * @throws SQLException 
     */
    public static DataSource getSource() throws SQLException{
    if(isTran_local.get()){//--如果开启过事务,则返回改造的DataSource,改造为每次调用getConnection都返回同一个开启过事务的Conn
    return (DataSource) Proxy.newProxyInstance(source.getClass().getClassLoader(), source.getClass().getInterfaces()
    ,new InvocationHandler(){
    public Object invoke(Object proxy, Method method,
    Object[] args) throws Throwable {
    if("getConnection".equals(method.getName())){
    return proxyConn_local.get();
    }else{
        return method.invoke(source, args);
    }
    }
    });
    }else{//--没有开启过事务,返回普通的数据源
        return source;
    }
    }
    /**
     * 释放资源 
     */
    public static void release(){
    DbUtils.closeQuietly(realconn_local.get());//--之前连接是没有关闭的在release的时候真正的关闭连接
    realconn_local.remove();
    proxyConn_local.remove();
    isTran_local.remove();
    }
}

service,dao的工厂类

生成service代理,根据注解确定在Service方法执行之前和之后做一些操作

public class BasicFactory {
    private static BasicFactory factory = new BasicFactory();
    private static Properties prop = null;
    private BasicFactory(){}
    static{
        try {
            prop = new Properties();
            prop.load(new FileReader(BasicFactory.class.getClassLoader().getResource("config.properties").getPath()));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    public static BasicFactory getFactory(){
        return factory;
    }
    
     /**
     * 获取Service的方法
     */
    @SuppressWarnings("unchecked")
    public <T extends Service> T getService(Class<T> clazz){
    try{
        //--根据配置文件创建具体的Service
        String infName = clazz.getSimpleName();
        String implName = prop.getProperty(infName);
        final T service = (T) Class.forName(implName).newInstance();
        //--为了实现AOP,生成service代理,根据注解确定在Service方法执行之前和之后做一些操作,比如:事务管理/记录日志/细粒度权限控制....
        T proxyService =  (T) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces()
         , new InvocationHandler(){
        //根据注解控制事务
        public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {
        if(method.isAnnotationPresent(Tran.class)){//如果有注解,则管理事务:
         try{
            TransactionManager.startTran();//--开启事务
            Object obj = method.invoke(service, args);//--真正执行方法
            TransactionManager.commit();//--提交事务
            return obj;
            }catch (InvocationTargetException e) {
                TransactionManager.rollback();//--回滚事务
                throw new RuntimeException(e.getTargetException());
            } catch (Exception e) {
                TransactionManager.rollback();//--回滚事务
                throw new RuntimeException(e);
            }finally{
                TransactionManager.release();//--释放资源
            }
        }else{//如果没有注解,则不管理事务,直接执行方法
            return method.invoke(service, args);
          }
        }
     });
             
         return proxyService;
  }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
            }
        }
        /**
         * 获取dao的方法
         */
        public <T extends Dao> T getDao(Class<T> clazz){
        try{
        String infName = clazz.getSimpleName();
        String implName = prop.getProperty(infName);
        return (T) Class.forName(implName).newInstance();
    }catch (Exception e) {
     e.printStackTrace();
     throw new RuntimeException(e);
    }
  }
}

Dao中不需要再考虑事务啦

public class UserDaoImpl implements UserDao {
    public void addUser(User user) {
        String sql = "insert into users values(null,?,?,?,?,?,?,?,null)";
        try{
            QueryRunner runner = new QueryRunner(TransactionManager.getSource());
            runner.update(sql,user.getUsername(),user.getPassword(),user.getNickname(),user.getEmail(),user.getRole(),user.getState(),user.getActivecode());
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    public User findUserByName(String username) {
        String sql = "select * from users where username = ?";
        try{
            QueryRunner runner = new QueryRunner(TransactionManager.getSource());
            return runner.query(sql, new BeanHandler<User>(User.class),username);
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
时间: 2024-12-25 07:54:25

面向切面编程aop的相关文章

Web项目中静态代理和动态代理为基础的面向切面编程AOP

本来每天更新的,我一般喜欢夜里过了十二点的时候发文章,结果难道是愚人节吗?学校的网也很有意思,断了,把我给耍了...好吧-开始今天的话题AOP.AOP太重要了,所以放到第二篇文章来谈这个话题,AOP是Spring中的重要概念.如果这个不理解Web开发中的三大框架的原理,那就呵呵了.时常听到同学和网友议论Web程序员大部分时间都是在考皮XML配置,我当时听到也是醉了,所以我要用心学习Web,其实这里面蕴含的设计模式.算法.架构思想在源码中体现的淋漓尽致啊,一个大宝库竟然视而不见可惜了.下面就一起品

面向切面编程——Aop

一.概念 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术.它是一种新的方法论,它是对传统OOP编程的一种补充. 二.Aop原理 1.面向对象编程模型 OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分.面向对象编程是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等

Spring(四):面向切面编程AOP

横切关注点:分布于应用中多处的功能 面向切面编程AOP:将横切关注点与业务逻辑相分离 在使用面向切面编程时,仍在一个地方定义通用功能,但是可以通过声明的方式定义这个功能以何种方式在何处应用,而无需修改受影响的类. 横切关注点可以被模块化为特殊的类,这些类被称为切面. 好处: 每个关注点集中于一处,而不是分散到多处代码中 服务模块更加简洁,因为它们只包含主要关注点的代码,次要关注点被转移到切面中了 1.定义AOP术语 1.1.通知(Advice) 切面的工作被称为通知. 通知定义了切面是什么以及何

spring中面向切面编程(AOP)的个人理解

面向切面编程AOP,是spring的一大特点 Aspect切面:封装共性功能的(增强功能的)类 Advice通过:切面类中封装的增强功能的方法. PointCut:切入点,是一个集合的概念,该集合的表达使用一个正则表达式表达 所有核心业务对象的所有方法的前后(事务处理AOP典型的应用) JoinPoint:连接点,程序中需要加入advice的地方,而且正在执行的ponitCut 织入(Weaving):将aspect和核心业务对象,进行整合的过程. 通过特定接口实现AOp Aop通知的类型: B

【串线篇】面向切面编程AOP

面向切面编程AOP 描述:将某段代码“动态”的切入到“指定方法”的“指定位置”进行运行的一种编程方式 (其底层就是Java的动态代理)spring对其做了简化书写 场景: 1).AOP加日志保存到数据库 2).AOP做权限验证,filter能做的它都能 3).AOP做安全检查 4).AOP做事务控制 AOP专业术语: 原文地址:https://www.cnblogs.com/yanl55555/p/11744089.html

Spring面向切面编程(AOP)

1 spring容器中bean特性 Spring容器的javabean对象默认是单例的. 通过在xml文件中,配置可以使用某些对象为多列. Spring容器中的javabean对象默认是立即加载(立即实例化:spring加载完成,立即创建对象) scope:属性 singleton:默认值为单例,默认也是立即加载,在加载完成spring容器的时候,bean对象已经创建完成 prototype:多例的,默认懒加载,spring容器加载完成的时候,不会创建bean的对象,只有从容器获得bean对象的

Spring之面向切面编程AOP(二)

简介 当积累的知识点到一定量的时候,学新知识就变得容易多了.希望再接下来的学习顺利进行下去.今天知识也是挺简单的,主要就是AOP面向切面编程.其中牵涉到了JDKProxy和CGLIB两个代理类,如何使用好,加以深刻理解.学起Spring切面编程也就简单多了 代理模式 1. 代理模式介绍 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对

面向切面编程AOP之动态代理

动态代理的作用是:最终是为了学习AOP(面向切面编程):    拓展一下:OOP是什么?  OOP是面向对象编程!! 面向切面--->与装饰者模式有点相似 --->比装饰者模式还要灵活 学习动态代理,我们只需要学习一下一个类即可 Proxy类,并对该类下的一个静态方法newProxyInstance()进行学习 直接上代码:

转:面向切面编程AOP的理解

AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合.不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能.日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性.异常处理和透明的持续性也都是如此,这种散布在各