Spring(六)AOP-02

(1)配置文件

 public interface IUserDao {
     public int addrUser();
     public int updateUser();
 }
public class UserDaoImpl implements IUserDao {

    @Override
    public int addrUser() {
        System.out.println("UserDaoImpl.addUser()");
        return 1;
    }

    @Override
    public int updateUser() {
        System.out.println("UserDaoImpl.updateUser()");
        return 1;
    }
}
public interface IUserService {
    public boolean addUser();
    public boolean updateUser();
    
}
public class UserServiceImpl implements IUserService {
    //应该用spring进行解耦,本次重点在于代理,故简化操作
    private IUserDao userDao = new UserDaoImpl();
    
    @Override
    public boolean addUser() {
        System.out.println("UserServiceImpl.addUser()");
        boolean flag = false;
        int rowAffect = userDao.addrUser();
        if(rowAffect==1) {
            flag = true;
        }
        return flag;
    }

    @Override
    public boolean updateUser() {
        System.out.println("UserServiceImpl.updateUser()");
        boolean flag = false;
        int rowAffect = userDao.updateUser();
        if(rowAffect==1) {
            flag = true;
        }
        return flag;
    }

}

切面类

/**
 * 切面
 * @author Administrator
 *
 */
public class TransactionManager {
    //前置通知方法
    public void begin(JoinPoint jp) {
        System.out.println("begin transaction");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
    }
    
    //后置通知方法
    public void commit(JoinPoint jp,Object flag) {
        System.out.println("commit transaction");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
        System.out.println("目标方法的返回值-->"+flag);
    }
    //异常通知方法
    public void rollback(JoinPoint jp,Exception ex) {
        System.out.println("rollback transaction");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
        System.out.println("目标方法抛异常-->"+ex.getMessage());
    }
    //最终通知
    public void finallyClose(JoinPoint jp) {
        System.out.println("finallyClose");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
    }
    //环绕通知  能控制目标方法的执行
    public Object around(ProceedingJoinPoint pjp)throws Throwable {
        Object retVal=null;
        try {
            System.out.println("around  begin transaction");
            System.out.println("目标对象-->"+pjp.getTarget());
            System.out.println("目标方法-->"+pjp.getSignature().getName());
            System.out.println("目标方法参数-->"+pjp.getArgs()[0]);
            //if() {
                //就是直接指定目标方法
                retVal = pjp.proceed();
            //}
            System.out.println("around  commit transaction");
        }catch(Exception e) {
            e.printStackTrace();
            System.out.println("around  rollback transaction");
        }finally {
            System.out.println("around  finallyClose");
        }
        
        return retVal;
    }
}

配置文件

<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util 
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    <!-- 实例化业务模型对象 -->
    <bean id="userDao" class="com.hdu.dao.impl.UserDaoImpl"></bean>
    
    <bean id="userService" class="com.hdu.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
    
    <!-- 实例化切面的对象 -->
    <bean id="tm" class="com.hdu.aspect.TransactionManager"></bean>
    
    <!-- spring 独有的配置,创建代理对象和确定如何横切切面 -->
    <!-- <aop:config>这个标签就告知spring要做代理对象了
            原则:如果实际对象有接口就jdk动态代理生成代理对象;如果实际对象没有接口就用cglib动态代理生成代理对象
             可以人为改动proxy-target-class="true",强制用cglib
    -->
    <aop:config proxy-target-class="false">
        <!-- <aop:aspect 这个节点标签,告知spring使用哪个切面
                可以写多个<aop:aspect节点,可以使用多个横切
        -->
        <aop:aspect id="myAspect" ref="tm">
            <!-- 告知spring 把切面 切在哪些类的哪些方法上,切点可以写多个-->
            <aop:pointcut id="myPointCut"
                          expression="execution(* com.hdu.service..*.*(..))"/>
            <!-- 前置通知 -->
            <aop:before
                pointcut-ref="myPointCut"
                method="begin"/>
            <!-- 后置通知 
                属性returning="flag" flag对应的通知方法中的参数
            -->
            <aop:after-returning
                pointcut-ref="myPointCut"
                method="commit"
                returning="flag"/>
            <!-- 异常通知 
                属性throwing="ex"  ex对应的异常通知的方法的参数
            -->
            <aop:after-throwing
                pointcut-ref="myPointCut"
                method="rollback"
                throwing="ex"/>
                
            <!-- 最终通知 -->
            <aop:after
                pointcut-ref="myPointCut"
                method="finallyClose"/>
            <!-- 环绕通知 -->
<!--              <aop:around -->
<!--                 pointcut-ref="myPointCut" -->
<!--                 method="around"/>         -->
        </aop:aspect> 
        
    </aop:config>    
    
</beans>

测试

public class TestSpringAOP {
    @Test
    public void testMethod1() {
        //初始化spring容器 
        ApplicationContext context = new ClassPathXmlApplicationContext("resources/spring_aop.xml");
        UserService userService=context.getBean("userService",UserService.class);
        System.out.println(userService.getClass());
        userService.addUser(new User());
        
        //userDao不会被代理
        UserDao userDao=context.getBean("userDao",UserDao.class);
        System.out.print("userDao不会被代理"+userDao.getClass());
    }
}

我们获取对象,要么是对象地址,要么是代理:System.out.println(userService.getClass());从打印结果 class com.sun.proxy.$Proxy6 可知,目前使用的是jdk动态代理。其中UserService userService = (UserService) context.getBean(“userService”);执行时spring已经把UserService变成代理对象。在执行userService.addUser();业务方法时就会被invoke方法拦截。就被切点表达式expression="execution(* com.hdu.service….(…))"拦截。
切点表达式expression="execution(* com.hdu.service….(…))"匹配上了实现类,就会执行切面中通知。
    <aop:aspect id=“myAspect” ref=“tm”>
      <aop:before pointcut-ref=“myPointCut” method=“begin”/>
    </aop:aspect>
就找到TransactionManager类,找到before方法,并调用。也就是说只要程序满足切点表达式,就会调用切面的方法。最终我们就看到它不是真实的对象,而是一个代理对象。由代理去执行就会响应执行通知的方法。
(2)注解
切面类:
Spring(六)AOP-02

/**
 * 切面
 * @author Administrator
 *
 */
@Component("tm")
@Aspect
public class TransactionManager {
    //the pointcut expression
    @Pointcut("execution(* com.hdu.service..*.*(..))")
    private void myPointCut() {}// the pointcut signature
    
    //前置通知方法
    //@Before("myPointCut()")
    public void begin(JoinPoint jp) {
        System.out.println("begin transaction");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
    }
    
    //后置通知方法
    //@AfterReturning(pointcut="myPointCut()",returning="flag")
    public void commit(JoinPoint jp,Object flag) {
        System.out.println("commit transaction");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
        System.out.println("目标方法的返回值-->"+flag);
    }
    //异常通知方法
    //@AfterThrowing(pointcut="myPointCut()",throwing="ex")
    public void rollback(JoinPoint jp,Exception ex) {
        System.out.println("rollback transaction");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
        System.out.println("目标方法抛异常-->"+ex.getMessage());
    }
    //最终通知
    //@After("myPointCut()")
    public void finallyClose(JoinPoint jp) {
        System.out.println("finallyClose");
        System.out.println("目标对象-->"+jp.getTarget());
        System.out.println("目标方法-->"+jp.getSignature().getName());
        System.out.println("目标方法参数-->"+jp.getArgs()[0]);
    }

    //环绕通知  能控制目标方法的执行
    @Around("myPointCut()")
    public Object around(ProceedingJoinPoint pjp)throws Throwable {
        Object retVal=null;
        try {
            System.out.println("around  begin transaction");
            System.out.println("目标对象-->"+pjp.getTarget());
            System.out.println("目标方法-->"+pjp.getSignature().getName());
            System.out.println("目标方法参数-->"+pjp.getArgs()[0]);
            //if() {
                //就是直接指定目标方法
                retVal = pjp.proceed();
                
            //}
            System.out.println("around  commit transaction");
        }catch(Exception e) {
            e.printStackTrace();
            System.out.println("around  rollback transaction");
        }finally {
            System.out.println("around  finallyClose");
        }
        
        return retVal;
    }
}

配置文件

<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util 
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    <!-- 
        @Controller @Service @Repository @Component @Resource    @Autowired @Qualifier
     -->
    <!-- 实例化业务模型对象 -->
    <context:component-scan base-package="com.hdu.dao.impl"></context:component-scan>
    <context:component-scan base-package="com.hdu.service.impl"></context:component-scan>
    
    
    <!-- 实例化切面的对象 -->
    <context:component-scan base-package="com.hdu.aspect"></context:component-scan>
    
    <!-- spring 独有的配置,创建代理对象和确定如何横切切面
        @Aspect @Pointcut @Before @AfterReturning @AfterThrowing @After @Around
     -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

测试

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

import com.hdu.entity.User;
import com.hdu.service.UserService;


public class TestSpringAOP {
    @Test
    public void testMethod1() {
        //初始化spring容器 
        ApplicationContext context= new ClassPathXmlApplicationContext("resources/spring_aop.xml");
        UserService userService=context.getBean("userService",UserService.class);
        System.out.println(userService.getClass());
        userService.addUser(new User());//连接点 启动横切
    }
    

}

结果

class com.sun.proxy.$Proxy13
around  begin transaction
目标对象-->[email protected]
目标方法-->addUser
目标方法参数-->[email protected]
UserServiceImpl.addUser()
UserDaoImpl.addUser()
around  commit transaction
around  finallyClose