Spring框架总结(九)

三、AOP编程

关注点代码:除了业务代码以外的代码.比如开启事务,关闭事务,异常处理
核心业务代码:保存用户这一句才是重点.
例子如下:
// 保存一个用户
public void add(User user) {
Session session = null;
Transaction trans = null;
try {
session = HibernateSessionFactoryUtils.getSession(); // 【关注点代码】
trans = session.beginTransaction(); // 【关注点代码】

session.save(user); // 核心业务代码

trans.commit(); //…【关注点代码】

} catch (Exception e) {
e.printStackTrace();
if(trans != null){
trans.rollback(); //..【关注点代码】

}
} finally{
HibernateSessionFactoryUtils.closeSession(session); ////..【关注点代码】

}
}

为了提高代码效率,会让核心代码和业务代码分离.实现的方法就是代理模式.

名词解释:
AOP面向切面编程:
让关注点代码与业务代码分离(面向切面编程就是面向重复代码编程)
关注点:
很多重复代码形成的类和方法

切面:
关注点形成的类。(公共的类)
面向切面编程与面向接口编程:
面向切面编程比面向接口编程更加抽象,面向切面编程公有属性和行为,抽象为面向切面。
面向接口编程,各个对象的公共方法抽取出来,放到父类和接口当中,接口当中定义类的公用行为。
面向切面编程很多重复的功能,抽象出来,比如工厂类
应用:
面向切面编程用在后期优化的时候使用。
切入点(指定拦截的是哪个点,拦截哪些方法):
执行目标对象方法,动态植入切面代码。
可以通过切入点表达式,指定拦截哪些类的哪些方法。给指定的类在运行的时候植入切面类代码


Aop代理实现了两种,一种是jdk代理,一种是cglib代理.
Aop实现的其实是通过,切面类的拦截,从而进行动态代理,使得多个重复的代码和方法,抽象出来,增强代码的强壮性和代码的优化性能.

1、注解方式实现AOP编程

步骤:
1) 先引入aop相关jar文件 (aspectj aop优秀组件)
spring-aop-3.2.5.RELEASE.jar 【spring3.2源码】
aopalliance.jar 【spring2.5源码/lib/aopalliance】
aspectjweaver.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】
aspectjrt.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】

注意: 用到spring2.5版本的jar文件,如果用jdk1.7可能会有问题。
需要升级aspectj组件,即使用aspectj-1.8.2版本中提供jar文件提供。


2) bean.xml中引入aop名称空间

 1 <context:component-scan base-package="com.liuyang.annotation.proxy"></context:component-scan> 

3) 开启aop注解

 1 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 

4) 使用注解
@Aspect 指定一个类为切面类
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入点表达式

@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行

事例:

(1)建立UserDao

1    public interface UserDao {
2 
3     public void save();
4 
5 }

(2)建立MyUserDaoAop

1    @Component
2 public class MyUserDaoAop implements UserDao {
3 
4     @Override
5     public void save() {
6         System.out.println("******核心业务的实现*****");
7     }
8 
9 }

(3)建立AOP

 1    @Component
 2 // 指定当前类为切面类
 3 @Aspect
 4 public class Aop {
 5 
 6     // 指定切入点表单式: 拦截哪些方法; 即为哪些类生成代理对象
 7     @Pointcut("execution(* com.liuyang.annotation.proxy.*.*(..))")
 8     public void pointCut_() {
 9     }
10 
11     // 前置通知 : 在执行目标方法之前执行
12     @Before("pointCut_()")
13     public void begin() {
14         System.out.println("开始事务/异常");
15     }
16 
17     // 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】
18     @After("pointCut_()")
19     public void after() {
20         System.out.println("提交事务/关闭");
21     }
22 
23     // 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】
24     @AfterReturning("pointCut_()")
25     public void afterReturning() {
26         System.out.println("afterReturning()");
27     }
28 
29     // 异常通知: 当目标方法执行异常时候执行此关注点代码
30     @AfterThrowing("pointCut_()")
31     public void afterThrowing() {
32         System.out.println("afterThrowing()");
33     }
34 
35     // 环绕通知:环绕目标方式执行
36     @Around("pointCut_()")
37     public void around(ProceedingJoinPoint pjp) throws Throwable {
38         System.out.println("环绕前....");
39         pjp.proceed(); // 执行目标方法
40         System.out.println("环绕后....");
41     }
42 
43 }

(4)建立bean.xml

 1    <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xsi:schemaLocation="
 7         http://www.springframework.org/schema/beans
 8         http://www.springframework.org/schema/beans/spring-beans.xsd
 9         http://www.springframework.org/schema/context
10         http://www.springframework.org/schema/context/spring-context.xsd
11         http://www.springframework.org/schema/aop
12         http://www.springframework.org/schema/aop/spring-aop.xsd">
13 
14     <!-- 开启注解扫描 -->
15     <context:component-scan base-package="com.liuyang.annotation.proxy"></context:component-scan>
16 
17     <!-- 开启AOP注解模式 ,默认false采用jdk代理 -->
18     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
19 </beans>      

(5)建立非接口模式的代理

1    @Component
2 // 加入容器
3 @Scope("prototype")
4 public class OrderDao {
5 
6     public void save() {
7         System.out.println("-----核心业务:保存2222!!!------");
8     }
9 }

(6)建立测试

 1     public class TestAop {
 2 
 3     // 目标对象有实现接口,spring会自动选择“JDK代理”
 4     @Test
 5     public void testApp() {
 6         ApplicationContext aContext = new ClassPathXmlApplicationContext(
 7                 "com/liuyang/annotation/proxy/bean.xml");
 8         UserDao userDao = (UserDao) aContext.getBean("myUserDaoAop");
 9         System.out.println(userDao.getClass());// $Proxy001
10         userDao.save();
11     }
12 
13     // 目标对象没有实现接口, spring会用“cglib代理”
14     @Test
15     public void testCglib() {
16         ApplicationContext aContext = new ClassPathXmlApplicationContext(
17                 "com/liuyang/annotation/proxy/bean.xml");
18         OrderDao orderDao = (OrderDao) aContext.getBean("orderDao");
19         System.out.println(orderDao.getClass());
20         orderDao.save();
21     }
22 
23     @Deprecated
24     // 共性问题:如果目标对象有实现接口,在从容器中获取目标对象的时候,只能通过接口接收对象。
25     public void testApp2() {
26         ApplicationContext aContext = new ClassPathXmlApplicationContext(
27                 "com/liuyang/annotation/proxy/bean.xml");
28         // 错误代码: 只能用接口接收
29         UserDao userDao = (UserDao) aContext.getBean("myUserDaoAop");
30         System.out.println(userDao.getClass());// $Proxy001
31         userDao.save();
32     }
33 
34     @Test
35     public void testGetObj() throws Exception {
36         ApplicationContext aContext = new ClassPathXmlApplicationContext(
37                 "com/liuyang/annotation/proxy/bean.xml");
38         OrderDao orderDao1 = (OrderDao) aContext.getBean("orderDao");
39         OrderDao orderDao2 = (OrderDao) aContext.getBean("orderDao");
40 
41         System.out.println(orderDao1);
42         System.out.println(orderDao2);
43 
44     }
45 
46 }

 

posted @ 2017-03-15 20:13  北极的大企鹅  阅读(160)  评论(0编辑  收藏  举报
阅读 - 79万