目录
一、案例代码
1.IUserDao接口
package m_spring_aop;
public interface IUserDao {
void saveUser();
void findUser();
void updateUser();
}
2.UserDao实现类
package m_spring_aop;
import javax.annotation.Resource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
@Repository("userDao") //把对象添加到IOC容器中,声明这是一个持久层的对象 ,默认bean的名称 是类名,但是 第一个单词的首字母小写
public class UserDao implements IUserDao{
public void saveUser() {
System.out.println("保存用户");
}
public void findUser(){
System.out.println("查询用户");
}
public void updateUser(){
System.out.println("修改用户");
}
}
3.切面类TransactionAop
package m_spring_aop;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* 切面类
*
* 该 公共点代码 要在何时被调用
*
* 使用 切入点表达式
* 告诉了spring 在调用 哪个类的哪个方法的时候 去动态切入 公共点代码
*
*/
@Component //把该类对象添加到IOC容器中
@Aspect //指定该类为一个切面类
public class TransactionAop {
//【前置通知】 (会在 切入点表达式中匹配的方法 之前 执行 beginTransaction 方法)
@Before("execution(* m_spring_aop.UserDao.*(..))")
public void beginTransaction(){
System.out.println("开启事务");
}
//【后置通知】 (会在 切入点表达式中匹配的方法 之后 执行 commit 方法)
@After("execution(* m_spring_aop.UserDao.*(..))")
public void commit(){
System.out.println("提交事务");
}
}
4.spring.xml
<!-- 开启注解扫描 -->
<context:component-scan base-package="m_spring_aop"></context:component-scan>
<!-- 启动aop扫描 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
5.测试类
@Test
public void test1(){
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("m_spring_aop/spring.xml");
IUserDao proxy = (IUserDao)ac.getBean("userDao");
System.out.println(proxy.getClass());
proxy.findUser();
}
6.结果
class com.sun.proxy.$Proxy11
开启事务
查询用户
提交事务
7.结论
使用Spring的动态代理方式实现的AOP(面向切面编程)从SpringIOC容器中获取的对象不再是原始的UserDao对象了,而是Spring代理之后产生的代理对象
如果目标对象实现了接口,那么就用目标对象的接口来接收代理对象,用的代理方式为动态代理(JDK代理)
如果目标对象没有实现接口,那么就用目标对象的类来接收代理对象,用的代理方式为Cglib代理(子类代理)
二、Spring代理方式实现AOP的原理
1.切入点表达式
拦截指定的类,生成代理对象,动态植入关注点代码
execution(
modifiers-pattern? 拦截的方法的访问修饰符
ret-type-pattern 方法返回类型,必须指定
declaring-type-pattern? 拦截的方法所在的类name-pattern(param-pattern)
拦截的方法以及方法的参数列表
throws-pattern? 方法声明的异常
)
//拦截 dao 包下面的 userDao中的 以 save开头的方法
execution(* com.joinlabs.dao.UserDao.save*(..))