Spring AOP学习笔记

2019-05-09  本文已影响0人  青年心路

一、AOP

1.什么是 AOP

AOP:Aspect-Oriented Programming面向切面编程,是面向对象编程的一种补充。
将程序中的交叉业务(事务,日志)代码提取出来,封装成切面,由AOP容器在合适的时机(位置)将封装的切面动态的织入到具体的业务逻辑中。
注意:AOP不是Spring特有的

1.1 应用场合

适用于具有横切逻辑的场合,如事务管理,日志记录,性能监测,异常通知,访问控制。

1.2 作用

1.3连接点

2. 实现原理

2.1 代理模式

2.1.1 概念

为其他对象提供一种代理,以控制对这个对象的访问,起到中介的作用。通过代理对象来访问目标对象,可以增强额外的操作,扩展目标对象的功能。

2.1.2 分类:

2.1.3 代理三要素

动态代理的两种技术

Proxy.newProxyInstance(
  classLoader,  //目标类的类加载器
  interfaces,  //目标类实现的接口
  InvacationHandler  //交叉业务逻辑
);

缺点:目标对象必须实现一个或多个接口,如果目标类没有实现接口则无法使用。

<!--cglib依赖-->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>${cglib.version}</version>
</dependency>
Enhancer.create(
    class,//目标类的类型
    InvocationHandler,//交叉业务逻辑
);

2.2 AOP原理

Spring AOP就是使用动态代理

3.Spring AOP的配置方式

3.1 三种配置方式

3.2 Advice类型

Spring AOP支持五种类型的通知

注意:多种Advice之间不能有耦合,即多个Advice之间不能有业务交叉

二、Spring AOP 1.x

1.基本用法

1.1添加jar包

<!--Spring AOP-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${spring.version}</version>
</dependency>

1.2 配置目标类

<!--配置目标类-->
<bean id="userServiceTarget" class="aop04.service.impl.UserServiceImpl"/>

1.3 配置Advice

定义增强类,并实现相同接口

<!--配置增强类-->
<bean id="logAdvice" class="aop04.advice.LogAdvice"/>

1.4 配置Pointcut

定义切入点,配置位置信息,指定哪些类的哪些方法需要被增强
使用NameMatchMethodPointcutAdvisor对Pointcut进行Advice
Advisor是Pointcut+Advice的配置器,Advisor=Pointcut+Advice

<!--配置要增强的切入点,织入的过程-->
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    <!--指定Advice-->
    <property name="advice" ref="logAdvice"/>
    <!--配置切入点,指定要匹配的方法名-->
    <property name="mappedNames">
        <list>
            <value>login</value>
            <value>logout</value>
        </list>
    </property>
</bean>

1.5 配置代理

使用ProxyFactoryBean配置代理

<!--配置代理-->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="userServiceTarget"/><!--目标类的实例-->
    <property name="interfaces"><!--目标类的接口列表-->
        <list>
            <value>aop04.service.UserService</value>
        </list>
    </property>
    <property name="interceptorNames"><!--交叉业务逻辑-->
        <list>
            <value>logAdvisor</value>
        </list>
    </property>
</bean>

三、Spring AOP 2.x

1.简介

基于命名空间的配置,原理时使用后处理器,配置更简单

特点:

2.基本用法

2.1配置Advice

定义增强类,不需要实现任何接口,但有多种写法


写法

2.2配置Pointcut并进行织入

四、AspectJ表达式

1.简介

切入点表达式,一种表达式,用来定义切入点的位置

2.用法

2.1within

语法:within(包名.类名)
匹配该类中的所有方法

2.1.1 具体实现

<!--Spring AOP 2.x-->

<!--配置目标类-->
<bean id="userService" class="aop06.service.impl.UserServiceImpl"/>

<!--配置Advice-->
<bean id="logAdvice" class="aop06.advice.LogAdvice"/>

<!--配置切入点,并进行织入-->
<aop:config>
    <!--配置切入点-->
    <aop:pointcut id="pc" expression="within(aop06.service.impl.UserServiceImpl)"/>
    <!--织入-->
    <aop:aspect ref="logAdvice">
        <!--将logAdvice中的log方法以前置通知的方式织入到对应的切入点中-->
        <!--<aop:before method="log" pointcut-ref="pc"/>-->

        <!--<aop:after-returning method="log2" pointcut-ref="pc" returning="returnValue"/>-->

        <!--<aop:after-throwing method="log3" pointcut-ref="pc" throwing="e"/>-->

        <aop:around method="log4" pointcut-ref="pc"/>
    </aop:aspect>
</aop:config>

2.2 execution

匹配特定包中的特定类中的特定返回值类型的特定参数的特定方法。
语法:execution(表达式)
表达式:返回值类型 包名 类名 方法名(参数类型)
通配符:*和..

<!--匹配返回值类型为void并且在aop06包下的service下的impl下的ProductServiceImpl实现类下的deleteById方法并且参数为int类型-->
<aop:pointcut id="pc2" expression="execution(void aop06.service.impl.ProductServiceImpl.deleteById(int))"/>
<!--匹配任意返回值类型并且在aop06包下的service包下的impl包中的任意类中的任意方法并且参数列表也是任意的-->
<aop:pointcut id="pc3" expression="execution(* aop06.service.impl.*.*(..))"/>

五、IoC的注解

1.简介

Spring中提供了一系列的注解,来替代配置文件中的配置
实际开发中,建议使用注解+配置文件的形式

2.IoC注解使用

2.1 步骤:

<!--扫描包,可以扫描多个-->
<context:component-scan base-package="ioc"/>
<context:component-scan base-package="com.hxx"/>

2.2 常用注解

2.2.1 组件的定义

@Value("666")
private int num;

@Value("true")
private Boolean flag;

@Value("${jdbc.username}")
private String username;

@Value("java.lang.String")
private Class clazz;

@Value("classpath:ioc/applicationContext.xml")
private Resource resource;
<!--读取属性文件-->
<!--<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="ioc/info.properties"/>
</bean>-->
<context:property-placeholder location="classpath:ioc/info.properties"/>

其他bean的引用

/**
 * 方式1:使用@Autowired
 *      自动装配:默认按byType,如果有多个同类型的bean,则按照byName
 *      结合Qualifier按照指定byName注入
 * 方式2:使用@Resource,javaEE提供
 */
//@Autowired
//@Qualifier("ob")
@Resource
private OtherBean otherBean;

集合的装配

//集合的装配使用@Resource注解,默认按照名字进行装配
@javax.annotation.Resource
private Integer[] arrays;

@javax.annotation.Resource
private List<OtherBean> list;

@javax.annotation.Resource
private Set<OtherBean> set;

@javax.annotation.Resource
private Map<OtherBean,Class> map;

@javax.annotation.Resource
private Properties p;
<!--集合类型的装配-->
<util:list id="arrays">
    <value>1</value>
    <value>2</value>
    <value>3</value>
</util:list>

<util:list id="list">
    <ref bean="otherBean"/>
    <ref bean="otherBean"/>
    <ref bean="ob"/>
    <bean class="ioc.OtherBean">
        <property name="msg" value="嘻嘻嘻"/>
    </bean>
</util:list>

<util:set id="set">
    <ref bean="otherBean"/>
    <ref bean="otherBean"/>
    <ref bean="ob"/>
    <bean class="ioc.OtherBean">
        <property name="msg" value="嘻嘻嘻"/>
    </bean>
</util:set>

<util:map id="map">
    <entry key-ref="otherBean" value="java.lang.String"/>
</util:map>

<util:properties id="p">
    <prop key="key1">value1</prop>
    <prop key="key2">value2</prop>
</util:properties>
//相当于init-method属性
@PostConstruct
public void init(){
    System.out.println("SpringBean.init");
}

//相当于destroy-method属性
@PreDestroy
public void destroy(){
    System.out.println("SpringBean.destroy");
}

六、AOP的注解

1.配置Advice

定义增强类,添加@Component和@Aspect

@Component
@Aspect //表示这是一个切面
public class LogAdvice {

    //定义切点表达式
    @Pointcut("execution(* aop.service.impl.*ServiceImpl.*(..))")
    public void pc(){
    }

    @Pointcut("execution(* aop.service.impl.*.*(..))")
    public void pc2(){
    }

    /*@Before("pc()")
    public void before(JoinPoint joinPoint){
        System.out.println("LogAdvice.before,name:"+joinPoint.getSignature().getName()+
                ",args:"+ Arrays.toString(joinPoint.getArgs())+",target:"+joinPoint.getTarget());
    }

    @AfterReturning(value = "pc()",returning = "returnValue")
    public void afterReturning(JoinPoint joinPoint,Object returnValue){
        System.out.println("LogAdvice.afterReturning,returnValue:"+returnValue);
    }

    @AfterThrowing(value = "pc2()",throwing = "e")
    public void afterThrowing(JoinPoint joinPoint,Exception e){
        System.out.println("LogAdvice.afterThrowing,e"+e);
    }*/

    @Around("pc()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知执行前。。。");
        Object proceed = joinPoint.proceed();
        System.out.println("环绕通知执行后。。。");
        return proceed;
    }

}

2.配置Pointcut并指定通知的类型

@Pointcut(切点表达式)

@Before(切点方法+())
@AfterReturning()
@AfterThrowing()
@Around()

3.织入

    <!--
        自动创建代理,并织入到切面
        proxy-target-class默认值是false,为JDK的动态代理
                                true代表使用CGLIB
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
上一篇下一篇

猜你喜欢

热点阅读