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)注解
切面类:
/**
* 切面
* @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