AOP开发

8.1 aop思想

oop(面向对象编程):面向对象,就是纵向地将事物给封装成类,里面具有这种事物的属性和行为。当别人想用到这种事物时,就通过构造它的一个实例对象来获得。体现出一种封装性。

aop(面向切面编程)横向地对不同事物的抽象,属性与属性,方法与方法,对象与对象都可以组成一个切面。简单来说,aop思想就是可以将某些类里的属性方法等抽取出来进行处理,组成一个新方法。

下面来张图说明一下:

AOP开发_第1张图片

可以看到,这里有2个对象A和B,它们各自有对应的方法。现在,我想用B对象里的方法对A对象方法进行处理(增强扩展A对象方法)。那么我就会重新创建一个对象出来作为A对象的代理(Proxy)对象,这个对象,他就来实现A对象方法的处理。这就是Aop体现的思想。

8.2 aop思想模拟

来段代码实现上图

首先,创建目标对象service

public class UserServiceImpl implements UserService {

    public void show1() {
        System.out.println("show1....");
    }
    public void show2() {
        System.out.println("show2....");
    }
    public void show3() {
        System.out.println("show3....");
    }
}

然后创建Myadvice对象(对service增强)

public class MyAdvice {
        public void advice1(){
            System.out.println("前置增强方法.....");
        }
        public void advice2(){
            System.out.println("后置增强方法.....");
        }
}

随后创建代理对象。这里代理对象通过实现BeanPostProcessor的postProcessAfterInitialization方法进行增强处理

public class MockBeanPostProfessor implements BeanPostProcessor, ApplicationContextAware {

    //要想获取Myadvice实例对象,就得用ApplicationContext的getBean方法来从Spring容器中获得
    ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //先进行筛选
        if(bean.getClass().getPackage().getName().equals("com.demo.service.impl")){//只要是这个包里的
            //生成service对象的代理对象
            Object beanProxy=Proxy.newProxyInstance(
                    bean.getClass().getClassLoader(),
                    bean.getClass().getInterfaces(),
                    (Object proxy, Method method,Object[] args)->{
                        //执行前置增强方法
                        MyAdvice myAdvice=applicationContext.getBean(MyAdvice.class);
                        myAdvice.advice1();
                        //执行service方法
                        Object result = method.invoke(bean, args);
                        //执行后置增强方法
                        myAdvice.advice2();
                        return result;
                    }
            );
            //返回增强结果
            return beanProxy;
        }
        //反之如果不是这个包的,那就不是想要增强的对象,返回自身即可
        return bean;
    }
}

执行一下:

AOP开发_第2张图片

8.3 aop相关概念
概念 单词 解释
目标对象 Target 被增强的方法所属对象
代理对象 Proxy 对目标对象进行增强后的对象,客户端实际调用的对象
连接点 Joinpoint 目标对象中可以被增强的方法(基本都可以被增强)
切入点 Pointcut 目标对象中可以被增强的方法
通知\增强 Advice 增强部分的代码逻辑
切面 Aspect 增强和切入点的组合
织入 Weaving 将增强和切入点的组合进行动态组合的过程
8.4 基于xml配置的aop
8.4.1 快速入门

1.2.引入aop相关依赖

2.准备目标类和增强类并配置给Spring管理

3.配置切入点和切面

4.配置织入

1.引入aop相关依赖

<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.4</version>
</dependency>

234.配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           
	   //aop命名空间
       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

	   //aop地址
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       ">


<!--目标类-->
    <bean id="userService" class="com.demo.service.impl.UserServiceImpl"></bean>
<!--增强类-->
    <bean id="myAdvice" class="com.demo.advice.MyAdvice"></bean>

<!--配置切点,在此之前要先去创建aop的命名空间(上面)-->
    <aop:config>
        <!--配置切点表达式,指定哪些方法被增强-->
        <aop:pointcut id="Mypointcut" expression="execution(void com.demo.service.impl.UserServiceImpl.show1())"/>
        <!--配置织入,将哪些切点与哪些增强进行结合-->
        <aop:aspect ref="myAdvice">
            <aop:before method="advice1" pointcut-ref="Mypointcut"></aop:before>
        </aop:aspect>

    </aop:config>

</beans>

执行

AOP开发_第3张图片

8.4.2 配置细说

1.切点表达式

execution(【修饰符,可省略】返回类型 包名.类名.方法名(参数) )

返回类型、某一级包名、类名、方法名,可以使用*来表示任意

包名与类名之间使用… 表示该包及其子包下的类

参数可用…表示任意参数

2.通知类型

通知名称 配置方式 执行时机
前置通知 < aop:before > 目标方法执行之前
后置通知 < aop:after-returning > 目标方法执行之后执行,若目标方法异常则不执行
环绕通知 < aop:around > 目标方法执行前后执行,若目标方法异常,环绕后方法不执行
异常通知 < aop:after-throwing > 目标方法抛出异常时执行
最终通知 < aop:after > 不管目标方法是否有异常,最终都会执行

其中就拿环绕通知做个例子:

//通知的环绕方法
public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
            System.out.println("前置增强方法.....");
            //执行目标方法
            Object proceed = proceedingJoinPoint.proceed();
            System.out.println("后置增强方法.....");
            return proceed;
        }
<!--配置切点,在此之前要先去创建aop的命名空间-->
<aop:config>
        <!--配置切点表达式,指定哪些方法被增强-->
        <aop:pointcut id="Mypointcut" expression="execution(void com.demo.service.impl.UserServiceImpl.show1())"/>
        <!--配置织入,将哪些切点与哪些增强进行结合-->
        <aop:aspect ref="myAdvice">
            <aop:around method="around" pointcut-ref="Mypointcut"/>
        </aop:aspect>

</aop:config>

另外:除了aspect这种配置方式外,还可以通过advisor方式。不过多解释了。

8.5 基于注解的aop
8.5.1 快速入门

相关配置:

<!--组件扫描-->
    <context:component-scan base-package="com.demo"></context:component-scan>

<!--目标类-->
    <bean id="userService" class="com.demo.service.impl.UserServiceImpl"></bean>
<!--增强类-->
    <bean id="myAdvice" class="com.demo.advice.MyAdvice"></bean>
<!--开启aop自动代理!!!!-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

目标方法:

@Service("userService")
public class UserServiceImpl implements UserService {

    public void show1() {
        System.out.println("show1....");
    }
    public void show2() {
        System.out.println("show2....");
    }
    public void show3() {
        System.out.println("show3....");
    }
}

增强方法:

@Component
@Aspect
public class MyAdvice {
        @Before("execution(void com.demo.service.impl.UserServiceImpl.show1())")
        public void advice1(){
            System.out.println("前置增强方法.....");
        }
}
8.5.2 配置细说
@Component
@Aspect
public class MyAdvice {

        //将切点表达式抽取出来
        @Pointcut("execution(void com.demo.service.impl.UserServiceImpl.show1())")
        public void myPointcut(){}

        //使用切点表达式
        @Before("MyAdvice.myPointcut()")
        public void advice1(){
            System.out.println("前置增强方法.....");
        }
    
    	//其他。。没啥好说的,直接根据配置方式加上注解即可
}

你可能感兴趣的:(Java学习,java,spring,学习)