搜索

如何理解Spring的AOP?

发布网友 发布时间:2022-04-24 14:14

我来回答

3个回答

懂视网 时间:2022-05-02 03:34

class MyJdkProxy implements InvocationHandler { private UserDao userDao; public MyJdkProxy(UserDao userDao) { this.userDao = userDao; } public UserDao createProxy() { UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass() .getClassLoader(), userDao.getClass().getInterfaces(), this);//也可以使用匿名内部类 return proxy; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("save".equals(method.getName())){ System.out.println("==================权限校验==============="); return method.invoke(userDao, args); } return method.invoke(userDao, args); } }

技术分享

测试结果:

技术分享

2.1.3 CGLIB动态代理原理

技术分享

技术分享

代理类MyCglibProxy:

public class MyCglibProxy implements MethodInterceptor{
 
 private OrderDao orderDao;
 
 public MyCglibProxy(OrderDao orderDao) {
 this.orderDao = orderDao;
 }

 public OrderDao createProxy(){
 // 1.创建一个CGLIB的核心类:
 Enhancer enhancer = new Enhancer();
 // 2.设置父类:
 enhancer.setSuperclass(orderDao.getClass());
 // 3.设置回调:
 enhancer.setCallback(this);
 // 4.生成代理 :
 OrderDao proxy = (OrderDao) enhancer.create();
 return proxy;
 }

 @Override
 public Object intercept(Object proxy, Method method, Object[] args,
  MethodProxy methodProxy) throws Throwable {
 if("update".equals(method.getName())){
  long begin = System.currentTimeMillis();
  System.out.println("开始时间:=========="+begin);
  
  Object obj = methodProxy.invokeSuper(proxy, args);
  
  long end = System.currentTimeMillis();
  System.out.println("结束时间:=========="+end);
  return obj;
 }
 return methodProxy.invokeSuper(proxy, args);
 }
}

技术分享

测试结果:

技术分享

2.2 Spring的传统AOP的开发

2.2.1 Spring传统AOP中定义的通知类型

AOP的概念是由AOP联盟组织提出的。AOP联盟为通知Advice定义了接口org.aopalliance.aop.Interface.Advice

Spring中按照通知Advice在目标类方法的连接点位置,可分为5类:

  1. 前置通知:org.springframework.aop.MethodBeforeAdvice 在目标方法执行前实施增强
  2. 后置通知:org.springframework.aop.AfterReturningAdvice 在目标方法执行后实施增强
  3. 环绕通知:org.aopalliance.intercept.MethodInterceptor 在目标方法执行前后实施增强
  4. 异常抛出通知:org.springframework.aop.ThrowsAdvice 在方法抛出异常后实施增强
  5. 引介通知:org.springframework.aop.IntroductionInterceptor 在目标类中添加一些新的方法和属性

2.2.2 Spring传统AOP中定义的切面类型

  1. Advisor:代表一般切面,其中的通知Advice本身就是一个切面,对目标类所有方法进行拦截。(不带切入点切面:增强所有方法)
  2. PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类哪些方法。(带有切入点切面:增强某些方法)
  3. IntroductionAdvisor:代表引介切面,针对引介通知而使用切面。(不要求掌握)

2.2.3 方式一:基于ProxyFactoryBean的代理

2.2.3.1 不带切入点切面的开发

步骤一:引入jar包

在引入Spring IOC开发包(6个)以及与JUnit整合的测试包(1个)的基础上,还要引入如下2个包:

  • AOP联盟的开发包:com.springsource.org.aopalliance-1.0.0.jar
  • spring的AOP的开发包:spring-aop-3.2.0.RELEASE.jar
  • 技术分享

    步骤二:创建包结构

    com.itheima.spring.demo3
      ProductDao
      ProductDaoImpl

    这里目标类ProductDaoImpl实现了一个接口ProductDao

    步骤三:注入目标类

    src目录下创建spring配置文件,完成Dao的注入

    <!-- 配置目标类: -->
    <bean id="productDao" class="com.itheima.spring.demo3.ProductDaoImpl"/>

    步骤四:定义通知Advice类

    使用Spring传统AOP中定义的一般切面,即不带切入点的切面,来增强目标类中的所有方法。

    public class MyBeforeAdvice implements MethodBeforeAdvice{
    
     @Override
     public void before(Method method, Object[] args, Object target)
      throws Throwable {
     System.out.println("==============前置通知=============");
     }
    
    }

    步骤五:在Spring中配置通知

    在spring配置文件中配置:

    <!-- 配置通知:(前置通知) -->
    <bean id="beforeAdvice" class="com.itheima.spring.demo3.MyBeforeAdvice"></bean>

    因为没有切入点,所以这里通知Advice本身就是一个切面,所以不需要额外配置切面。(切面=切入点+通知)

    步骤六:配置对目标类DAO生成代理

    这里要在spring配置文件中配置ProxyFactoryBean类的bean。

    首先了解一下ProxyFactoryBean常用可配置属性:

  • target:代理的目标对象
  • proxyInterfaces:代理要实现的接口。如果多个接口可以使用以下格式赋值:<list><value></value>....</list>
  • proxyTargetClass:是否对类代理而不是接口,设置为true时,使用CGLib代理
  • interceptorNames:需要织入目标的Advice
  • singleton:返回代理是否为单实例,默认为单例
  • optimize:当设置为true时,强制使用CGLib(在配置了proxyInterfaces默认使用jdk动态代理情况下)
  • 配置对目标类生成代理:

    <!-- 配置生成代理 -->
    <bean id="productDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
     <!-- 配置目标类 -->
     <property name="target" ref="productDao"/>
     <!-- 配置类的实现的接口,这里只有一个接口 -->
     <property name="proxyInterfaces" value="com.itheima.spring.demo3.ProductDao"/>
     <!-- 配置切面(这里通知即切面),要拦截的名称(因为这里interceptorNames要的是名称而不是对象,所以使用value而不是ref)-->
     <property name="interceptorNames" value="beforeAdvice"/>
    </bean>

    步骤七:编写测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class SpringDemo3 {
    
     // @Resource(name = "productDao")
     // 注入代理类:
     @Resource(name="productDaoProxy")
     private ProductDao productDao;
    
     @Test
     public void demo1() {
     productDao.save();
     productDao.update();
     productDao.delete();
     productDao.find();
     }
    }

    测试结果:

    技术分享

    2.2.3.2 带切入点切面的开发

    步骤一:引入jar包

    同2.2.1.3步骤一

    步骤二:创建包结构

    com.itheima.spring.demo4

      CustomerDao

    这里目标类CustomerDao没有实现接口

    步骤三:注入目标类

    src目录下创建spring配置文件,完成Dao的注入:

    <!-- 配置目标类 -->
     <bean id="customerDao" class="com.itheima.spring.demo4.CustomerDao"/>

    步骤四:定义通知类

    这里MethodInterceptor是环绕通知:

    public class MyAroundAdvice implements MethodInterceptor{
    
     @Override
     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
     System.out.println("环绕前通知=================");
     // 执行目标方法:
     Object obj = methodInvocation.proceed();
     System.out.println("环绕后通知=================");
     return obj;
     }
    
    }

    步骤五:在Spring中配置通知

    <!-- 配置通知:(环绕通知) -->
    <bean id="myAroundAdvice" class="com.itheima.spring.demo4.MyAroundAdvice"/>

     步骤六:在Spring中配置带有切入点的切面

    因为这里是带有切入点的切面,针对部分方法进行增强,而不是针对所有方法,所以需要进行切面配置。

    查看Spring传统AOP中定义带有切入点的切面PointCutAdvisor接口的实现类:

    技术分享

    下面演示配置正则表达式方法带有切入点的切面实现类:RegexpMethodPointcutAdvisor。需要使用正则表达式配置哪些类的哪些方法需要进行增强。

    <!-- 配置带有切入点的切面 -->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     <!-- 属性pattern值是一个正则表达式。-->
     <!-- 拦截所有方法:.:任意字符 *:任意次数 -->
     <!-- <property name="pattern" value=".*"/> -->
     <!-- 拦截某一个方法,点在正则中需要被转义成普通的文本 -->
     <!-- <property name="pattern" value="com.itheima.spring.demo4.CustomerDao.update"/> -->
     <!-- 多个切入点使用patterns,切入点用逗号分隔 -->
     <!-- <property name="patterns" value="com.itheima.spring.demo4.CustomerDao.update, com.itheima.spring.demo4.CustomerDao.delete"/> -->
     <!-- 多个切入点的简写形式 -->
     <property name="patterns" value=".*save.*, .*update.*"/>
     <!-- 配置通知 -->
     <property name="advice" ref="myAroundAdvice"/>
    </bean>

    步骤六:配置对目标类DAO生成代理

    <!-- 配置生成代理 -->
    <bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
     <!-- 配置目标 -->
     <property name="target" ref="customerDao"/>
     <!-- 配置代理目标类 -->
     <property name="proxyTargetClass" value="true"/>
     <!-- 配置切面 -->
     <property name="interceptorNames" value="myAdvisor"/>
    </bean>

    步骤八:编写测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class SpringDemo4 {
    
     // @Resource(name = "customerDao")
     // 注入代理对象
     @Resource(name="customerDaoProxy")
     private CustomerDao customerDao;
    
     @Test
     public void demo1() {
     customerDao.save();
     customerDao.update();
     customerDao.delete();
     customerDao.find();
     }
    }

    测试结果:

    技术分享

    2.2.3.3 基于ProxyFactoryBean代理的缺点

    配置麻烦,需要为每一个要增强的类配置一个ProxyFactoryBean,通过其target标签指定要增强的目标类。

    2.2.4 方式二:自动代理

    由于ProxyFactoryBean方式配置麻烦,一般情况下我们采用自动代理的方式。

    2.2.4.1 Spring传统AOP自动代理的方式

    BeanNameAutoProxyCreator:根据Bean名称创建代理,针对所有连接点都有效,不带切入点,所以不配置切面 

    DefaultAdvisorAutoProxyCreator:根据Advisor本身包含的信息创建代理,可以指定接入点

    AnnotationAwareAspectJAutoProxyCreator:基于Bean的AspectJ注解进行自动代理(重点,见3)

    2.2.4.2 自动代理与ProxyFactoryBean对比

    基于ProxyFactoryBean代理是先有被增强的目标类对象 ,将目标类的bean传递给ProxyFactoryBean,生成代理对象:

    技术分享

    基于ProxyFactoryBean代理注入时需要注入代理对象。

    自动代理是基于BeanPostProcessor(后处理bean),是在bean的生成过程中对bean进行增强,在类实例化的过程中就产生了代理对象。

    自动代理注入时需要注入目标对象。

    2.2.4.3 基于Bean名称的自动代理(不带切入点):BeanNameAutoProxyCreator

    将ProxyFactoryBean代理的spring配置文件进行修改,只留下目标类和通知:

    <!-- 配置目标类: -->
    <bean id="productDao" class="com.itheima.spring.demo3.ProductDaoImpl"/>
    <bean id="customerDao" class="com.itheima.spring.demo4.CustomerDao"/>
    
    <!-- 配置通知:(前置通知) -->
    <bean id="beforeAdvice" class="com.itheima.spring.demo3.MyBeforeAdvice"/>
    <!-- 配置通知:(环绕通知) -->
    <bean id="myAroundAdvice" class="com.itheima.spring.demo4.MyAroundAdvice"/>

    配置对所有的DAO目标类生产代理:

    <!-- 配置基于Bean名称的自动代理。因为基于后处理bean,可以没有ID,由Spring内部进行调用生产代理对象 -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
     <!-- 配置Bean名称 -->
     <property name="beanNames" value="*Dao"/>
     <!-- 配置切面,因为该方式针对所有连接点都有效,所以没有切入点,通知即切面 -->
     <property name="interceptorNames" value="beforeAdvice"/>
    </bean>

    测试类:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext2.xml")
    public class SpringDemo5 {
     @Resource(name="productDao")//注入目标对象
     private ProductDao productDao;
     
     @Resource(name="customerDao")
     private CustomerDao customerDao;
     
     @Test
     public void demo1(){
     productDao.save();
     productDao.update();
     productDao.delete();
     productDao.find();
     
     customerDao.save();
     customerDao.update();
     customerDao.delete();
     customerDao.find();
     }
    }

    测试结果:

    技术分享

    2.2.4.4 基于切面信息的自动代理(带切入点):DefaultAdvisorAutoProxyCreator

    将ProxyFactoryBean代理的spring配置文件进行修改,只留下目标类和通知:

    <!-- 配置目标类: -->
    <bean id="productDao" class="com.itheima.spring.demo3.ProductDaoImpl"/>
    <bean id="customerDao" class="com.itheima.spring.demo4.CustomerDao"/>
    
    <!-- 配置通知:(前置通知) -->
    <bean id="beforeAdvice" class="com.itheima.spring.demo3.MyBeforeAdvice"/>
    <!-- 配置通知:(环绕通知) -->
    <bean id="myAroundAdvice" class="com.itheima.spring.demo4.MyAroundAdvice"/>

    配置切面:

    <!-- 配置切面,采用正则表达式方式带有切入点切面实现类 -->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     <!-- 表达式,定义切入点 -->
     <property name="pattern" value="com.itheima.spring.demo4.CustomerDao.save"/>
     <!-- 配置通知 -->
     <property name="advice" ref="myAroundAdvice"/>
    </bean>

    配置生成代理:

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

    测试类:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext3.xml")
    public class SpringDemo6 {
    
     @Resource(name="productDao")
     private ProductDao productDao;
     
     @Resource(name="customerDao")
     private CustomerDao customerDao;
     
     @Test
     public void demo1(){
     productDao.save();
     productDao.update();
     productDao.delete();
     productDao.find();
     
     customerDao.save();
     customerDao.update();
     customerDao.delete();
     customerDao.find();
     }
    }

    测试结果:

    技术分享

    2.3 Spring传统AOP总结

    1、Spring的传统AOP底层使用JDK或者Cglib产生代理

      如果类实现了接口:使用JDK动态代理。

      如果类没有实现接口:使用cglib生成代理。

    2、基于ProxyFactoryBean代理方式

      不带有切点切面

      带有切入点切面

    3、基于BeanPostProcessor的自动代理

      基于Bean名称自动代理

      基于切面信息的自动代理

    4、自动代理和基于ProxyFactoryBean代理模式的区别

      自动代理:在类的实例对象生成过程中产生代理,返回就是代理对象。注入的时候需要注入目标对象

      基于ProxyFactoryBean代理:先有被代理实例对象 , 将被代理对象作为参数传递给ProxyFactoryBean,产生代理对象。注入的时候需要注入代理对象

     3 Spring基于AspectJ的AOP(重点)

    3.1 AspectJ的概述

    AspectJ是一个基于Java语言的AOP框架。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

    Spring为了简化AOP开发引入了AspectJ作为自身AOP的开发。

    Spring2.0以后新增了对AspectJ切入点表达式的支持。

    @AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。

    在新版本Spring框架中,建议使用AspectJ方式来开发AOP。

    3.2 AspectJ注解方式的AOP开发

    3.2.1 开发过程

    步骤一:创建web项目,引入jar包

    在引入Spring IOC开发包(6个),与JUnit整合的测试包(1个),AOP联盟的开发包(1个)以及spring的AOP的开发包(1个)的基础上,还要引入:

  • AspectJ本身jar包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar。路径:spring-framework-3.0.2.RELEASE-dependenciesorg.aspectjcom.springsource.org.aspectj.weaver1.6.8.RELEASE
  • spring支持aspectj的包:spring-framework-3.2.0.RELEASElibsspring-aspects-3.2.0.RELEASE.jar
  • 技术分享

    步骤二:创建Spring的配置文件

    在src目录下创建,引入Spring的Bean和AOP约束:

    <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"
     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">

    步骤三:创建包结构

    com.itheima.spring.demo1

      OrderDao

    这里目标类没有实现接口。

    步骤四:将目标类配置到Spring中

    <!-- 目标类 -->
    <bean id="orderDao" class="com.itheima.spring.demo1.OrderDao"/>

    步骤五:编写切面类

    切面 = 通知 + 切入点

    AspectJ注解提供的通知类型有:

    1. @Before:前置通知,相当于Spring传统AOP的MethodBeforeAdvice
    2. @AfterReturning:后置通知,相当于Spring传统AOP的AfterReturningAdvice
    3. @Around:环绕通知,相当于Spring传统AOP的MethodInterceptor
    4. @AfterThrowing:抛出通知,相当于Spring传统AOP的ThrowAdvice
    5. @After:最终final通知,不管是否异常,该通知都会执行
    6. @DeclareParents:引介通知,相当于Spring传统AOP的IntroductionInterceptor(不要求掌握)

    AspectJ注解的切入点表达式定义(用来哪些类的哪些方法需要进行增强):

    使用方式:@通知注解("execution(切入点表达式)")

    切入点表达式的语法:[访问修饰符(可省略)] 方法返回值 方法名(参数)

    例如:

    execution(public * com.itheim.spring.demo1.OrderDao.save(..))

    execution(* *.*(..))

    execution(public * com.itheim.spring.demo1.*.*(..))

    execution(public * com.itheim.spring.demo1..*.*(..))

    execution(public * com.itheim.spring.demo1.OrderDao+.*(..))//包含子类

    编写切面类:

    @Aspect
    public class MyAspectAnno {
    
     // 定义通知和切入点: 
     @Before("execution(* com.itheima.spring.demo1.OrderDao.save(..))")
     public void before(){//方法名可以是任意的
     System.out.println("前置通知================");
     }
    }

    步骤六:在Spring配置文件中开启AspectJ的注解

    <!-- 开启AspectJ的注解 -->
    <aop:aspectj-autoproxy/>

    步骤七:将切面类配置到Spring中

    <!-- 配置切面类 -->
    <bean class="com.itheima.spring.demo1.MyAspectAnno"/>

    步骤八:编写测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class SpringDemo1 {
    
     @Resource(name="orderDao")
     private OrderDao orderDao;
     
     @Test
     public void demo1(){
     orderDao.save();
     orderDao.update();
     orderDao.delete();
     orderDao.find();
     }
    }

    3.2.2 AspectJ注解的通知类型的具体使用

    3.2.2.1 前置通知 @Before

    代表在切入点方法之前执行增强

    方法参数Joinpoint:获得切入点信息

    代码示例:

    //单独定义切入点
    @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.save(..))")
    private void pointcut2(){}
    
    //定义前置通知并使用切入点
    @Before("MyAspectAnno.pointcut2()")
    public void before(JoinPoint joinPoint){
     System.out.println("前置通知================"+joinPoint);
    } 

    3.2.2.2 后置通知@AfterReturning

    代表在切入点方法之后执行增强

    因此方法参数可以获得切入点方法的返回值

    方法参数JoinPoint:获得切入点信息

    代码示例:

    //后置通知
    @AfterReturning(value="execution(* com.itheima.spring.demo1.OrderDao.update(..))",returning="result")
    public void afterReturning(Object result){
     System.out.println("后置通知================"+result);
    }

    3.2.2.3 环绕通知@Around

    代表在切入点方法之前和之后执行增强,用来控制目标方法的执行

    方法参数ProceedingJoinPoint:获得切入点信息

    代码示例:

    // 环绕通知
    @Around("execution(* com.itheima.spring.demo1.OrderDao.delete(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
     System.out.println("环绕前通知===============");
     // 执行目标方法:
     Object obj = joinPoint.proceed();//不调用该方法就会阻止目标方法的执行
     System.out.println("环绕后通知===============");
     return obj;
    }

    3.2.2.4 异常抛出通知@AfterThrowing

    代表在切入点方法出现异常的时候执行增强

    方法参数JoinPoint:获得切入点信息

    方法参数Throwable:获得到异常的信息

    代码示例:

    // 异常抛出通知
    @AfterThrowing(value="execution(* com.itheima.spring.demo1.OrderDao.find(..))",throwing="e")
    public void afterThrowing(Throwable e){
     System.out.println("异常抛出通知=============="+e.getMessage());
    }

    3.2.2.5 最终通知@After

    代表无论切入点方法是否出现异常,该通知总是会执行,类似try{}catch(){}finally{}

    方法参数JoinPoint:获得切入点信息

    代码示例:

    // 最终通知
    @After(value="execution(* com.itheima.spring.demo1.OrderDao.find(..))")
    public void after(){
     System.out.println("最终通知================");
    }

    3.2.3 AspectJ注解的切入点定义

    @Pointcut(value="execution(* com.itheima.spring.demo1.OrderDao.find(..))")
    private void pointcut1(){}

    注意使用private而不是public。

    使用定义的切入点:

    // 异常抛出通知:
    @AfterThrowing(value="MyAspectAnno.pointcut1()",throwing="e")
    public void afterThrowing(Throwable e){
     System.out.println("异常抛出通知=============="+e.getMessage());
    }
    
    // 最终通知
    @After("MyAspectAnno.pointcut1()")
    public void after(){
     System.out.println("最终通知================");
    }

    3.3 AspectJ的XML方式的AOP开发

    3.3.1 开发过程

    步骤一:创建web项目,引入jar包

    同3.2.1步骤一。

    步骤二:创建Spring的配置文件

    同3.2.1步骤二。

    步骤三:创建包结构

    com.itheima.spring.demo2
      CustomerDao
      CustomerDaoImpl

    这里目标类CustomerDaoImpl实现了接口CustomerDao

    步骤四:将目标类配置到Spring中

    <!-- 配置目标类 -->
    <bean id="customerDao" class="com.itheima.spring.demo2.CustomerDaoImpl"/>

    步骤五:编写切面类

    public class MyAspectXml {
     public void before(){
     System.out.println("前置通知==============");
     }
    }

    注意这里只定义了通知,没有定义切入点,切面(切入点+通知)的完整配置在spring配置文件中进行,见步骤七。

    步骤六:将切面类配置到Spring中

    <!-- 配置切面类 -->
    <bean id="myAspectXml" class="com.itheima.spring.demo2.MyAspectXml"/>

    步骤七:在Spring中进行完整的AOP配置

    这里可以配置个切入点和多个通知的组合

    <!-- 配置完整AOP -->
    <aop:config>
     <!-- 配置切入点 --> 
     <aop:pointcut expression="execution(* com.itheima.spring.demo2.CustomerDao+.save(..))" id="pointcut1"/>
     <!-- 配置切面,里面可以配置多个通知,关联多个切入点 -->
     <aop:aspect ref="myAspectXml">
     <aop:before method="before" pointcut-ref="pointcut1"/>
     </aop:aspect>
    </aop:config>

    步骤八:编写测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext2.xml")
    public class SpringDemo2 {
    
     @Resource(name="customerDao")
     private CustomerDao customerDao;
     @Test
     public void demo1(){
     customerDao.save();
     customerDao.update();
     customerDao.delete();
     customerDao.find();
     }
    }

    3.3.2 AspectJ的XML方式的通知和切入点配置

    <!-- 配置AOP -->
    <aop:config>
     <!-- 定义多个切入点 -->
     <aop:pointcut expression="execution(* com.itheima.spring.demo2.CustomerDao+.save(..))" id="pointcut1"/>
     <aop:pointcut expression="execution(* com.itheima.spring.demo2.CustomerDao+.update(..))" id="pointcut2"/>
     <aop:pointcut expression="execution(* com.itheima.spring.demo2.CustomerDao+.delete(..))" id="pointcut3"/>
     <aop:pointcut expression="execution(* com.itheima.spring.demo2.CustomerDao+.find(..))" id="pointcut4"/>
     <!-- 配置多个通知和切入点的组合 -->
     <aop:aspect ref="myAspectXml">
     <aop:before method="before" pointcut-ref="pointcut1"/>
     <aop:after-returning method="afterReturing" pointcut-ref="pointcut2" returning="result"/>
     <aop:around method="around" pointcut-ref="pointcut3"/>
     <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="e"/>
     <aop:after method="after" pointcut-ref="pointcut4"/>
     </aop:aspect>
    </aop:config>

    3.4 Advisor和Aspect区别

    Advisor:Spring传统的切面,一般都是由一个切入点和一个通知的组合。
    Aspect:Aspect是真正意义上的切面,是由多个切入点和多个通知组合。

    4 Spring的JDBC模板类

    4.1 Spring的持久层模板类

    Spring提供了很多持久层技术的模板类来简化编程:

    技术分享

    4.2 Spring JDBC模板类的使用示例

    步骤一:创建web项目,引入jar包

    在引入Spring IOC开发包(6个)的基础上,还要引入3个包:

  • 数据库驱动包
  • Spring JDBC模板包:spring-jdbc-3.2.0.RELEASE.jar
  • Spring事务包:spring-tx-3.2.0.RELEASE.jar
  • 技术分享

    步骤二:创建数据库

    create database spring_day02;

    步骤三:编写测试类

    public class SpringDemo1 {
     @Test
     public void demo1(){
     // 创建连接池,使用spring内置连接池DriverManagerDataSource
     DriverManagerDataSource dataSource = new DriverManagerDataSource();
     dataSource.setDriverClassName("com.mysql.jdbc.Driver");
     dataSource.setUrl("jdbc:mysql:///spring_day02");
     dataSource.setUsername("root");
     dataSource.setPassword("123");
     // 创建Spring JDBC模板类对象
     JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
     //使用Spring模板类对象执行SQL语句
     jdbcTemplate.execute("create table user (id int primary key auto_increment,name varchar(20))");
     }
    }

    4.3 Spring整合DAO层和JDBC模板的开发

    在src下创建Spring配置文件applicationContext1.xml,然后在4.2的基础上进行

    4.3.1 在Spring中配置连接池

    4.3.1.1 spring的内置连接池

    <!-- 配置Spring的内置连接池 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
     <property name="url" value="jdbc:mysql:///spring_day02"/>
     <property name="username" value="root"/>
     <property name="password" value="123"/>
    </bean>

    4.3.1.2 DBCP连接池

    引入DBCP连接池的jar包:

  • com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
  • com.springsource.org.apache.commons.pool-1.5.3.jar
  • 然后配置DBCP连接池:

    <!-- 配置DBCP连接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
     <property name="url" value="jdbc:mysql:///spring_day02"/>
     <property name="username" value="root"/>
     <property name="password" value="123"/>
    </bean>

    4.3.1.3 C3P0连接池

    引入C3P0连接池的jar包:

  • com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
  • 配置C3P0连接池:

    <!-- 配置C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
     var cpro_id = "u6292429";
     
    
    
    
                                            

    热心网友 时间:2022-05-02 00:42

    Spring的AOP面向切面编程,就是横向的,比如程序运行时都要建日志,相当于SQL的触发器。

    Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。

    Spring特点:

    1、方便解耦,简化开发

    通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

    2、AOP编程的支持

    通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。

    3、声明式事务的支持

    在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

    4、方便程序的测试

    可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。

    5、方便集成各种优秀框架

    Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。

    6、降低Java EE API的使用难度

    Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。

    7、Java 源码是经典学习范例

    Spring的源码设计精妙、结构清晰、匠心独运,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。

    热心网友 时间:2022-05-02 02:00

    首先楼主需要明白“事物处理”的概念
    AOP主要是针对事物处理来说吧,而且是相对于以前的编程式事物处理的,不用AOP的话,我们得通过硬编码的方式将事物处理写在方法中,有了AOP之后,我们只需要在spring的配置文件中配置一下事物就可以了,这就叫声明式事物处理.一般配置时是通过配置匹配某个格式的方法名,当运行到这种方法的时候spring就会拦截下它来,并给它加上事物的处理了
    通俗点讲spring的AOP相当与电脑中主板的作用。主板:就是把各种元器件连接到其上,统一由其管理,避免了元器件与与器件之间连接的混乱。
    不知这么说你有没有明白一些
    声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。
    E-MAIL:11247931@qq.com
    Top