springAOP之动态代理(三)

本文介绍了AOP(面向切面编程)的基本概念,并通过具体的代码示例详细讲解了如何利用Spring框架进行AOP编程,包括切入点、通知类型及其配置方式,同时展示了使用XML和注解两种方式来实现AOP。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AOP的相关概念

这里面的名词解释,可以结合上一章的内容(模拟Hibernate的事务处理和查看工资)来进行理解。
1. 切面
日志、安全性、权限类以及事务类,总之和业务逻辑没有关系的都可以做切面
2. 通知
切面中的方法。例如:事务中的beginTransaction和commit方法
3. 切入点
只有符合切入点,才能把通知和目标方法结合起来。例如:代理的判断语句

if("admin".equals(this.privilege.getAccess())){
        //调用目标类的目标方法
        method.invoke(this.iSalaryManage, args);
    }else{
        System.out.println("您没有权限");
    }


4. 连接点
客户端调用的方法

 proxy.showSalary();//代理对象的代理方法

AOP做到了代码的重用

springAOp切面编程的例子

结合上一节的“模拟Hibernate的事务处理”来进行拓展。因此,这里只粘贴部分代码。

Xml文件

使用AOP切面编程
1. 导入命名空间
2. 引入目标类

3. 定义切面类,过滤切入点。代理类的生成交给spring来完成
4. 设置通知方法

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!-- 
    使用AOP切面编程
    1. 导入命名空间
    2. 引入目标类
    3. 定义切面类,过滤切入点
    4. 设置通知方法
-->
<bean id="personDao" class="com.lzl.test.aop_proxy.PersonDaoImpl"></bean>
<bean id="transaction" class="com.lzl.test.aop_proxy.Transaction"></bean>
<aop:config>
    <!-- 切面类
        expression(切面表达式) 
        com.lzl.test.aop_proxy.personDaoImpl下面的所有方法
     -->
    <aop:pointcut expression="execution(* com.lzl.test.aop_proxy.PersonDaoImpl.*(..))" id="perform"/>
    <!--
        切面 
     -->
    <aop:aspect ref="transaction">
        <!-- 前置通知
             * 在目标方法执行之前
        -->
        <aop:before method="beginTransaction" pointcut-ref="perform"/>
        <!-- 后置通知
            * 在目标方法执行之后执行
            * 通过returning来获取返回的结果
            * 代理方法发生异常时,不执行该方法
         -->
        <aop:after-returning method="commit" pointcut-ref="perform" returning="val"></aop:after-returning>
        <!--
            最终通知
            * 目标方法执行之后
            * 无论是否发生异常,都会执行。类似于finally
            * 常用于资源的关闭等操作 
         -->
        <aop:after method="finallyMethod" pointcut-ref="perform"/>
        <!--
            异常通知
            * 目标方法发生异常时,触发该方法。
            * throwing抛异常的参数
         -->
        <aop:after-throwing method="throwEx" throwing="ex" 
        pointcut-ref="perform"></aop:after-throwing>
        <!-- 环绕通知
            * 在目标方法执行之前执行
            * 可以控制那些对象执行目标方法                
         -->
         <aop:around pointcut-ref="perform" method="arroundAdvice"></aop:around>
    </aop:aspect>
</aop:config>   
</beans>

切入点类

public class Transaction {
/**
 * 前置通知
 * @param joinPoint
 */
public void beginTransaction(JoinPoint joinPoint){
    joinPoint.getArgs(); //获取方法参数
    String methodName = joinPoint.getSignature().getName();
    System.out.println("=begin transaction...="+methodName);
}
/**
 * 后置通知
 * @param val
 */
public void commit(Object val){
    //List<Person> list = (List<Person>) val;
    //System.out.println("=commit...="+list.size());
    System.out.println("=commit...=");
}
/**
 * 最终通知
 */
public void finallyMethod(){
    System.out.println("finally Method...");
}
/**
 * 异常通知
 * @param ex
 */
public void throwEx(Throwable ex){
    System.out.println(ex.getMessage());
}
public void arroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
    String methodName = pjp.getSignature().getName();
    if("savePerson".equals(methodName)){
        pjp.proceed();
    }
}
}

测试类

public class PersonTest extends SpringHelper{
static{
    path="com/lzl/test/aop_proxy/applicationContext.xml";
}
@Test
public void test(){
    PersonDao personDao = (PersonDao) fileResource.getBean("personDao");
    personDao.selectPerson();
}
}

说明
如果目标类实现了接口,spring就用JDKproxy代理,如果没有实现接口,spring就使用cglib代理。
用SpringAOP重构查看工资的代码

代码的实现参照上一节。这里只粘贴修改的代码

<?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:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    <bean id="salaryManage" class="com.lzl.test.spring.salary.SalaryManageImpl"></bean>
    <bean id="logger" class="com.lzl.test.spring.salary.Logger"></bean>
    <bean id="privilege" class="com.lzl.test.spring.salary.Privilege"></bean>
    <bean id="security" class="com.lzl.test.spring.salary.Security"></bean>
    <!--
         一个切入点有多个切面
         通知方法执行的顺序,按照其配置的先后顺序来执行的。
     -->
    <aop:config>
    <!-- 定义的目标类及方法 -->
        <aop:pointcut expression="execution(* com.lzl.test.spring.salary.SalaryManageImpl.*(..))" id="perform"/>
        <!-- 切面 -->
        <aop:aspect ref="logger">
            <!-- 前置通知 
                日志系统
            -->
            <aop:before method="startLogger" pointcut-ref="perform"/>
        </aop:aspect>
        <aop:aspect ref="security">
            <!-- 前置通知 
                安全系统
            -->
            <aop:before method="startSecurity" pointcut-ref="perform"/>
        </aop:aspect>
        <aop:aspect ref="privilege">
            <!-- 前置通知
                权限验证
            -->
            <aop:before method="openPrivilege" pointcut-ref="perform"/>
        </aop:aspect>
    </aop:config>   
</beans>

测试类

public class SalaryTest extends SpringHelper{
static{
    path="com/lzl/test/spring/salary/applicationContext.xml";
}
@Test
public void test(){
    ISalaryManage sm = (ISalaryManage) fileResource.getBean("salaryManage");
    sm.showSalary();
}
}

AOP注解

使用注解的方式实现AOP切面编程。(仅供了解)
这个例子还是MVC的那个例子。在PersonDaoImpl中添加了事务的处理。这里只粘贴部分代码。

XML文件

<?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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <!--
        开启注解解析器
     -->
    <context:component-scan base-package="com.lzl.test.annotation.mvc.aop"></context:component-scan>
    <!-- 开启AOP的注解 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

事务类(切面类)

@Component("transaction")
@Aspect  //定义为切面类
public class Transaction {
    //切入点
    @Pointcut("execution(* com.lzl.test.annotation.mvc.aop.PersonDaoImpl.*(..))")
    private void aa(){} //方法签名  返回值必须是void 方法的修饰符最好是private
    @Before("aa()")
    public void beginTransaction(){
        System.out.println("=开启事务...=");
    }
    @AfterReturning("aa()")
    public void commit(){
        System.out.println("=关闭事务..=");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值