Spring Aop

  1. Aop

  1. 为什么学习 AOP
      1. 对程序进行增强:不修改源码的情况下.
      2. AOP 可以进行权限校验,日志记录,性能监控,事务控制.
      3. 对面向对象的思维方式的有力补充

这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程

 

面试的时候问到概念的东西怎么回答

方法1:举例

方法2: 画图

  • Aop能做的事情:

例如验证登陆,权限,性能检测,错误信息记录等等,AOP的目的就是将这些东西分离开来,让开发人员专注与核心关注点,下面用到一个简单的验证身份的例子。

  在登陆的时候,我们简单的将用户信息放置于session["User"]中,通常在实现一些关键操作的时候,都会记录用户的信息,所以每次都要判断一下session是否过期,但这动作应该由AOP来做

 

    1. 是对面向对象的思维方式的有力补充

我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。 也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程

 

Spring AOP的底层实现技术---

http://www.cnblogs.com/luotaoyeah/p/3778183.html

http://www.51cto.com/specbook/223/39480.htm

  1. Springaop

指挥Spring 帮我们生成代理对象

----Spring实现aop的原理

  jdk动态代理

    被代理对象必须要实现接口,才能产生代理对象

  cglib代理

-->jdk动态代理局限性,cglib代理(第三方代理技术)

 原理:对目标对象进行继承代理

(hibernate中查询的load方法创建时首先查询session缓存,没有就创建代理对象

要求 实体类不能被final修饰)

如果目标对象被final修饰,那么该类无法被cglib代理

有接口springaop优先使用 jdk动态代理,无使用cglib

/**

 * jdk动态代理

 * @author Administrator

 *

 */

public class MyJDKProxy implements InvocationHandler {

 

    /**

     * arg0 代理对象

     * arg1 调用的方法

     * arg2 方法的参数

     */

    @Override

    public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {

       System.out.println("打开事务");

        Object  object= arg1.invoke(userDao, arg2);

        System.out.println("提交事务");

       return object;

    }

 

    private UserDao userDao;

 

    public MyJDKProxy(UserDao userDao) {

       this.userDao = userDao;

    }

 

    // 编写工具方法:生成代理:

    public UserDao createProxy() {

       UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),

              userDao.getClass().getInterfaces(), this);

       return userDaoProxy;

    }

 

}

 

  1. Spring基于AspectJ的AOP开发
  1. AOP开发的相关术语

JoinPoint(连接点) 

PointCut(切入点) 

Advice (通知)

Target(目标对象)

Weaving(织入) 

     Proxy(代理)

Aspect(切面)

 

  1. 通知类型

前置通知 :在目标方法执行之前执行.

后置通知 :在目标方法执行之后执行

环绕通知 :在目标方法执行前和执行后执行

异常抛出通知:在目标方法执行出现 异常的时候 执行

最终通知 :无论目标方法是否出现异常 最终通知都会 执行.

 

  1. 切入点表达式

execution(表达式)

  1. Spring AOP配置与应用API 6.2.3.4.
  • 添加jar

  1. 两种方式:
    1. 使用Annotation
    2. 使用xml

 

使用Annotation

applicationContext.xml中添加 <aop:aspectj-autoproxy />

切入点表达式的写法:

    关键字:execution(表达式)

    表达式:

            访问修饰符  返回值  包名.包名.包名...类名.方法名(参数列表)

    标准的表达式写法:

            public void com.vp.service.impl.AccountServiceImpl.saveAccount()

    访问修饰符可以省略

            void com.vp.service.impl.AccountServiceImpl.saveAccount()

    返回值可以使用通配符,表示任意返回值

            * com.vp.service.impl.AccountServiceImpl.saveAccount()

    包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.

            * *.*.*.*.AccountServiceImpl.saveAccount())

    包名可以使用..表示当前包及其子包

            * *..AccountServiceImpl.saveAccount()

    类名和方法名都可以使用*来实现通配

            * *..*.*()

    参数列表:

            可以直接写数据类型:

            基本类型直接写名称           int

            引用类型写包名.类名的方式   java.lang.String

    可以使用通配符表示任意类型,但是必须有参数

            可以使用..表示有无参数均可,有参数可以是任意类型

    全通配写法:

            * *..*.*(..)

   

    实际开发中切入点表达式的通常写法:

        切到业务层实现类下的所有方法

        * com.vp.service.impl.*.*(..)

 

 

Xml代码

  <!--  开启spring的注解 -->

  <context:annotation-config />

<!--   开启扫描器 -->

<context:component-scan base-package="com.demo" />

<!-- 开启aop的注解 -->

<aop:aspectj-autoproxy />

 

添加日志

@Aspect

@Component

public class Logging {

    // 定义切入点

    @Pointcut("execution(public * com.demo.service..*.*(..))")

    public void mythod() {

    }

 

    /**

     * 在业务方法运行之前运行

     */

    @Before("mythod()")

    public void before() {

       System.out.println("日志开始记录.......");

    }

 

    @After("mythod()")

    public void after() {

       System.out.println("日志记录结束");

    }

 

    @Around("mythod()")

    public Object aroud(ProceedingJoinPoint pjp) throws Throwable {

       System.out.println("环绕...");

       Object object = pjp.proceed();

       return object;

    }

 

}

 

注意:环绕通知织入的方法如果有返回值 需要

 

    1. @Before 发放执行之前织入
    2. @AfterReturning 方法正常执行完返回之后织入(无异常)
    3. @AfterThrowing 方法抛出异常后织入
    4. @After 类似异常的finally
    5. @Around 环绕 类似filter , 如需继续往下执行则需要像filter中执行FilterChain.doFilter(..)对象一样 执行 ProceedingJoinPoint.proceed()方可,例子如下:

@Around("execution(* com.demo.dao..*.*(..))")

public void before(ProceedingJoinPoint pjp) throws Throwable{

System.out.println("method start");

pjp.proceed();//类似FilterChain.doFilter(..)告诉jvm继续向下执行

}

  1. xml配置AOP  6.3.1

applicationContext.xml

<!-- 创建日志bean -->

    <bean id="logging" class="com.vp.logging.Logging"></bean>

    <aop:config>

       <!-- 定义切面 相当于注解版在类前面添加@Aspect -->

       <aop:aspect id="logg" ref="logging">

           <!-- 定义切入点 -->

           <aop:pointcut expression="execution(public * com.demo.service..*.*(..))"

              id="mm" />

           <aop:before method="before" pointcut-ref="mm" />

           <aop:after method="after" pointcut-ref="mm" />

           <aop:around method="aroud" pointcut-ref="mm" />

       </aop:aspect>

    </aop:config>

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值