Johnny

博观而约取
厚积而薄发

Aop面向切面编程

1.png

什么是面向切面编程

官方:在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
个人理解:面向切面编程旨在较少冗余代码,使用的是一种代码横向抽取(举例:不同的方法拥有三句同样的代码,那这个代码就可以抽取出来,但使用父类、接口、继承、实现会极大的提高代码的耦合度,因此我们采用面向切面编程,把这三句代码全部抽取到一个方法当中)

xml配置版

实例代码

接口:

public interface Hello {
    void sayHello();
}

实现类

public class HelloImpl implements  Hello {
    @Override
    public void sayHello() {
        System.out.println("hello");
    }
}

增强(相当于抽取出来的部分代码)

public class BuildHello {
    void beforeBuilder(){
        System.out.println("start...");
    }

    void afterBuilder(){
        System.out.println("ending...");
    }
}

xml中bean实例的配置

    <!-- 配置一个目标对象-->
    <bean id="hello" class="com.soft1851.spring.aop.hello.HelloImpl"/>
    <!--配置一个前置增强对象-->
    <bean id="beforeAdvice" class="com.soft1851.spring.aop.hello.BuildHello"/>

    <!--aop配置,配置切点,切点表达式,增强的注入-->
    <aop:config >
        <aop:aspect id="before" ref="beforeAdvice">
            <!--切点配置|-->
            <aop:pointcut id="beforeCut" expression="execution(* com.soft1851.spring.aop.hello..*.*(..))"/>
            <!--增强的注入-->
            <aop:before method="beforeBuilder" pointcut-ref="beforeCut"/>
        </aop:aspect>

        <aop:aspect id="after" ref="beforeAdvice">
            <aop:pointcut id="afterCut" expression="execution(* com.soft1851.spring.aop.hello..*.*(..))"/>
            <aop:after-returning method="afterBuilder" pointcut-ref="afterCut"/>
        </aop:aspect>
    </aop:config>
注意要点:
  • aop-config是配置整体的切面编程,而aop-aspect是设置切点和增强的容器,aop-pointcun用于设置切点,aop:before用于设置前置增强,aop:after-returning用于设置后置增强

注解版

实例代码

dao底层代码

@Repository
public class ForumDaoImpl  implements ForumDao {

    private  JdbcTemplate jdbcTemplate;

    public ForumDaoImpl(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public List<Forum> selectAll() {
        String sql = "SELECT * FROM t_forum ";
        System.out.println(jdbcTemplate);
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Forum.class));
    }

    @Override
    public int insert(Forum forum) {
        System.out.println("开始插入数据");
        String sql = "INSERT INTO t_forum VALUES (Null,?)";
        Object[] args = {forum.getForumName()};
        return jdbcTemplate.update(sql, args);
    }

    @Override
    public int[] batchInsert(List<Forum> forums) {
        String sql = "INSERT INTO t_forum VALUES (NULL,?)";
        return jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
                preparedStatement.setString(1,forums.get(i).getForumName());
            }

            @Override
            public int getBatchSize() {
                return forums.size();
            }
        });
    }

    @Override
    public int delete(int forumId) {
        System.out.println("开始删除数据");
        String sql = "DELETE  FROM t_forum WHERE forum_id = ?";
        Object args = forumId;
        return jdbcTemplate.update(sql,args);
    }

    /**
     * 修改forum中的字段值
     * @param forum
     * @return
     */
    @Override
    public int update(Forum forum) {
        String sql = "UPDATE t_forum SET forum_name = ? WHERE forum_id = ?";
        Object[] args = {forum.getForumName(), forum.getForumId()};
        return jdbcTemplate.update(sql, args);
    }

    @Override
    public Forum get(int forumId) {
        String sql = " SELECT * FROM t_forum WHERE forum_id = ? ";
        Object[] args = {forumId};
        return jdbcTemplate.queryForObject(sql, args,new BeanPropertyRowMapper<>(Forum.class));
    }
}

增强类

@Aspect
public class MyAdvice {
    /**
     * 配置切点
     */
    @Pointcut("execution(* com.soft1851.spring.web.dao..*.insert*(..))")
    public void pointCut() {
    }

    /**
     * 配置前置增强
     */
    @Before("MyAdvice.pointCut()")
    public void beforeMethod() {
        System.out.println("等待数据插入");
    }

    /**
     * 配置后置增强
     */
    @AfterReturning("execution(* com.soft1851.spring.web.dao..*.*(..))")
    public void afterMethod(){
        System.out.println("关闭数据库");
    }
}

xml实例配置

    <bean name="forumDao" class="com.soft1851.spring.web.dao.impl.ForumDaoImpl"/>
    <bean name="myAdvice" class="com.soft1851.spring.web.interceptor.MyAdvice"/>
    <aop:aspectj-autoproxy/>
注意要点:
  • 增强类头部要写注解@Aspect
  • xml文件中照样还需要配置,只是配置代码减少
  • @afterReturning是后置增强(也就是中央代码执行结束后执行)

aop支持的切点

execution——匹配运行方法的连接点
within——使匹配连接点限定在特定类型
this——限定匹配的连接点是给定类型的实例
target——限定匹配连接点的目标是给定类型的实例
args——限定连接点的参数是给定类型的实例
@target——限定匹配的连接点的运行的对象有该类型的注解
@args——运行时传递的参数拥有给定类型的注解
@within——限定匹配给定指定注解类型的连接点
@annotation——限定连接点拥有指定的注解
bean——使得连接点匹配特质的bean或bean集合

exexction表达式

  • 匹配所有的公有方法
    execution(public (..))
  • 匹配所有以set开头的方法
    execution( set(..))
  • 匹配所有AccountService接口定义的方法
    execution( com.xyz.service.AccountService.(..))
  • 匹配所有service包内的方法
    execution(* com.xyz.service..(..))
  • 匹配所有service包以及子包内的方法
    execution(* com.xyz.service...(..))
  • 所有在service包内的连接点
    within(com.xyz.service.*)
  • 所有service包以及子包内的连接点
    within(com.xyz.service..*)
  • 所有实现AccountService接口的连接点
    this(com.xyz.service.AccountService)
  • 所有的目标对象实现AccountService接口的连接点
    target(com.xyz.service.AccountService)
  • 有一个参数并且运行时传入参数为Serializable的连接点
    args(java.io.Serializable)
  • 目标对象有@Transactional注解
    @target(org.springframework.transaction.annotation.Transactional)
  • 定义的目标对象类型含有@Transactional注解
    @within(org.springframework.transaction.annotation.Transactional)
  • 含有@Transactional注解的可运行方法
    @annotation(org.springframework.transaction.annotation.Transactional)
  • 含有一个参数并且在运行时传入的参数含有@Classified注解
    @args(com.xyz.security.Classified)
  • bean名字定义为tradeService的连接点
    bean(tradeService)
  • bean名字满足Service命名的所有连接点
    bean(Service)

总结

本文我们主要学习了如何使用XML配置方式来完成Spring AOP的使用。文章中我们学习了很多配置标签,完成了切面定义、切点定义以及多种增强方法的定义。至此我们已经掌握了Spring AOP的基本知识点,可在具体的项目开发中使用。不过学了那么多的知识点,我们还是需要一定的实践来进行消化吸收。

本原创文章未经允许不得转载 | 当前页面:Johnny-韩源-期待与你分享生活的每一天 » Aop面向切面编程

评论