Spring AOP
目录
AOP Aspect Oritened Programming 被称为面向切面编程
OOP Object Oritened Programming 被称为面向对象编程
1. 切面组件(Aspect Bean)
2. 切入点(pointcut)
3. 通知(Advice)
4. 目标组件(Target)
5. 动态代理(AutoProxy)
AOP使用方法
AOP分析
AOP案例
AOP注解配置
单元测试
Junit工具
Spring-test+Jnit
概念
AOP Aspect Oritened Programming 被称为面向切面编程。
OOP Object Oritened Programming 被称为面向对象编程。
面向对象编程侧重点为对象;
面向切面编程侧重点为切面。
在大量组件中寻找时间、地点、逻辑相同的层面。比如Dao所有方法前开启事务、Controller所有方法后xxxx。
面向切面编程是以面向对象编程为基础,考虑将共通业务处理进行隔离,独立封装,之后通过SpringAOP配置方式作用。
AOP优点:将传统业务和共通业务代码进行解耦。例如事务控制、权限控制、日志记录等。
1.切面组件(Aspect Bean)
封装共通处理的组件,将来会通过配置动态作用到其他业务组件方法上的功能。(要追加什么功能?)
2.切入点(pointcut)
用于指定哪些业务组件方法追加切面组件功能。Spring提供了多种切入点表达式,例如方法表达式、类型表达式、组件名称表达式等。(给谁加功能?)
方法表达式
execution(修饰符? 返回类型 方法名(参数) 抛出异常?) //匹配容器中所有bean中find开头的方法 execution(* find*(..)) //匹配DeptSerive组件中find开头的方法 execution(* cn.xdl.service.DeptSerive.find*(..)) //匹配cn.xdl.service包中所有类所有方法 execution(* cn.xdl.service.*.*(..)) //匹配cn.xdl.service包及子包中所有类所有方法 execution(* cn.xdl.service..*.*(..))
类型表达式
within(包名.类名) //匹配DeptService组件所有方法 within(cn.xdl.service.DeptService) //匹配cn.xdl.service包中所有类所有方法 within(cn.xdl.service.*) //匹配cn.xdl.service包及子包中所有类所有方法 within(cn.xdl.service..*)
bean名称表达式
bean(bean名字) //匹配id=deptService的bean对象的所有方法 bean(deptService) //匹配id以Service结尾的bean对象所有方法 bean(*Service)
3.通知(Advice)
用于指定业务组件和切面组件作用的时机。例如业务组件方法前、方法后、异常发生后等类型。(什么时候加?)
Spring框架提供以下几种通知:
前置通知 : 在目标方法前加切面功能
后置通知 : 在目标方法后加切面功能(目标方法正常结束)
最终通知 : 在目标方法后加切面功能(目标方法正常或不正常结束)
异常通知 : 在目标方法抛出异常后加切面功能
环绕通知 : 在目标方法前和后加切面功能
其他封装后的通知(例如事务等)
try{ //前置通知执行时机 //执行目标方法 //后置通知执行时机 }catch(){ //异常通知执行时机 }finally{ //最终通知执行时机 }
不同类型通知,对应切面组件的方法定义格式:
public void xxx(); //前置
public void xxx(参数); //后置
public void xxx(); //最终
public void xxx(Exception ex);//异常
public Object xxx(PrceedingJoinPoint pjp);//环绕
4.目标组件(Target)
要被追加切面组件功能的组件。即:切入点指定的组件。
5.动态代理(AutoProxy)
Spring AOP实现原理是采用动态代理技术完成的。Spring框架提供了两种生成代理对象的技术,分别是JDK Proxy API和CGLIB技术。
默认情况下有接口的目标组件采用JDK Proxy生成;没有接口的会采用CGLIB技术生成。
CGLIB技术原理:根据现有组件动态创建一个子类组件,然后将父类所有方法进行重写,在重写方法时可以调用父类功能和切面追加功能。
public class EmpServiceImpl$$EnhancerBySpringCGLIB$$55949fc7 extends EmpServiceImpl{ public void add() { super.add();//调用父类add方法 loggerBean.mylog();//调用切面功能 } public void findAll() { super.findAll();//调用父类findAll方法 loggerBean.mylog();//调用切面功能 } }
JDK Proxy API技术原理:根据现有组件接口动态创建一个代理组件。然后将接口方法进行实现,在方法中可以调用父类功能和切面追加功能。
public class $Proxy6 implements DeptService{ public void add() { DeptServiceImpl.add();//调用组件方法 loggerBean.mylog();//调用切面功能 } }
提示:可以在aop配置时,强制指定cglib技术生成子类代理对象。
<aop:config proxy-target-class="true">
AOP使用方法
AOP分析
1. 追加的时机?--》选择哪种类型通知
2. 要追加什么功能?--》切面组件及其逻辑
3. 要给谁追加功能?--》指定切入点表达式
AOP案例
需求1:所有Service抛出异常,将异常信息记录到error.log文件中。
功能:将异常信息记录到error.log文件中
谁加:所有Service方法追加,bean(*Service)
时机:抛出异常,使用异常通知
AOP注解配置
单元测试
Junit工具
@Before、@Test、@After 每个@Test方法独立使用一个线程执行,其中某个出错,不会干扰其他方法执行。
Spring-test+Jnit
1.测试Spring容器中Bean对象
直接将Spring容器中某个Bean对象注入给Test类使用。 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:applicationContext.xml"}) public class MyJunitSpringTest { @Autowired DeptService service; @Test public void test1(){ service.add(); } }
2.测试SpringMVC处理流程
使用MockMvc发送请求,接收响应结果。
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:applicationContext.xml"}) public class TestDeptController { @Autowired private DeptController controller; @Test public void test1() throws Exception{ //创建一个mockMvc对象 MockMvc mock = MockMvcBuilders.standaloneSetup(controller).build(); //创建一个get请求/dept/xx RequestBuilder loadRequest = MockMvcRequestBuilders.get("/dept/{id}",10); //发送请求执行,获取执行结果 MvcResult result = mock.perform(loadRequest).andReturn(); //显示result结果信息 String str = result.getResponse().getContentAsString(); System.out.println(str); } }