spring_day03(代理模式,AOP原理,基于xml的AOP实现,基于注解的AOP实现)

一.动态代理

1.动态代理的特点  

*字节码随用随创建,随用随加载。 

*它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。 

*装饰者模式就是静态代理的一种体现。

2.两种动态代理方式:

*基于接口的动态代理:

  由jdk的Proxy类提供

  要求被代理类至少实现一个接口

*基于子类的动态代理:

  由第三方提供, CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。

  要求被代理类不是final

3.为什么使用动态代理:

*在不改变源码的基础上,增强被代理对象的方法。

二.AOP

1.作用

面向切面编程,spring代替程序猿,不必再编写代理模式,而是交给spring管理动态代理,来解耦方法间的依赖。

开发者只需要关注增强方法的部分。

2.术语

*Joinpoint(连接点): 有可能需要进行增强的方法

*Pointcut(切入点): 在所有有可能被增强的方法中,确实需要增强的方法

*Advice(通知/增强):增强方法的具体实现

         通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

*Aspect(切面): 切入点和通知的整合

*Weaving(织入):   是指把增强应用到目标对象来创建新的代理对象的过程。   spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入

3.步骤

*编写核心业务代码

*抽取重复代码,形成通知

*在xml配置文件中说明切入点与通知的织入,

*在运行阶段,交给spring管理,将通知织入到切入点当中,生成动态代理对象。

4.注意

spring根据切入点所在类是否为接口来判断,使用哪种代理方式。

三.基于xml的AOP实现

1.jar包

2.xml中导入aop约束

<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>

3.配置aop

 <!-- 配置 service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>

        <!-- 配置 dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> 
property name="dbAssit" ref="dbAssit"></property>
        </bean>
        <!-- 配置数据库操作对象 --> <bean id="dbAssit" class="com.itheima.dbassit.DBAssit">
<property name="dataSource" ref="dataSource"></property>
<!-- 指定 connection 和线程绑定 -->
<property name="useCurrentConnection" value="true"></property>
</bean>
        <!-- 配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///spring_day02"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>

4.将公共方法抽取为通知类

public class TransactionManager { 
};

5.把通知类用 bean 标签配置起来

 <!-- 配置通知 -->
<bean id="txManager" class="com.itheima.utils.TransactionManager">
<property name="dbAssit" ref="dbAssit"></property>
</bean> 

6.使用 aop:config 声明 aop 配置

aop:aspect:
 作用:   用于配置切面。  属性:   id:给切面提供一个唯一标识。   ref:引用配置好的通知类 bean 的 id。

<aop:aspect id="txAdvice" ref="txManager"> 
  <!--配置通知的类型要写在此处--> 
</aop:aspect> 

7.:使用 aop:pointcut 配置切入点表达式

aop:pointcut:  作用:   用于配置切入点表达式。就是指定对哪些类的哪些方法进行增强。  属性:   expression:用于定义切入点表达式。   id:用于给切入点表达式提供一个唯一标识

<aop:pointcut
        expression="execution(  public void com.itheima.service.impl.AccountServiceImpl.transfer(    java.lang.String, java.lang.String, java.lang.Float) )"
        id="pt1"/> 

 8.使用 aop:xxx 配置对应的通知类型

aop:before
 作用:   用于配置前置通知。指定增强的方法在切入点方法之前执行   属性:   method:用于指定通知类中的增强方法名称   ponitcut-ref:用于指定切入点的表达式的引用   poinitcut:用于指定切入点表达式

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

 *aop:before

*aop:after-returning

*aop:after-throwing

*aop:after

*aop:around环绕通知:用于实现自定义通知顺序

9.

<aop:config>
    <aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pt1"/>
    <aop:aspect id="txAdvice" ref="txManager">
        <!-- 配置环绕通知 -->
        <aop:around method="transactionAround" pointcut-ref="pt1"/>
    </aop:aspect>
</aop:config> 

9.通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。  execution(* com.itheima.service.impl.*.*(..))

 四.基于注解的AOP实现

 1.jar包

2.在配置文件中导入 context 的名称空间

 
 
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
</beans>
 

 3.:把资源使用注解配置

4.在配置文件中指定 spring 要扫描的包

<!-- 告知 spring,在创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"></context:component-scan> 

 5.把通知类也使用注解配置

6.在通知类上使用@Aspect 注解声明为切面

@Component("txManager")
@Aspect
//表明当前类是一个切面类
public class TransactionManager {
    定义一个 DBAssit
    @Autowired
    private DBAssit dbAssit;
}

 7.在增强的方法上使用注解配置通知

@Before
 作用:   把当前方法看成是前置通知。  属性:   value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@Before("execution(* com.itheima.service.impl.*.*(..))")
public void beginTransaction(){
        try{dbAssit.getCurrentConnection().setAutoCommit(false);
        }catch(SQLException e)
        {e.printStackTrace();}
        } 
 
 

 *@Before

*@AfterReturning

* @AfterThrowing

*@After

*@Around

8.在 spring 配置文件中开启 spring 对注解 AOP 的支持

<!-- 开启 spring 对注解 AOP 的支持 --> 
<aop:aspectj-autoproxy/>

注:不使用xml的方式

@Configuration
@ComponentScan(basePackages="com.itheima")
@EnableAspectJAutoProxy public class SpringConfiguration { }

9.@Pointcut和@Around:

*@Around的value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@Pointcut("execution(* com.itheima.service.impl.*.*(..))") private void pt1() {};

@Around("pt1()")//注意:千万别忘了写括号

猜你喜欢

转载自www.cnblogs.com/counter-biao/p/11614020.html