spring入门3-AOP

AOP 代理模式

引入:
静态代理模式:
spring入门3-AOP
dao层
1-1-0 接口:UserDao

package com.kuang.w.demo02.dao;
public interface UserDao {
    /**
     * class add()
     */
    void add();
    /**
     * class upTable
     */
    void upTable();
}

1-1-1 实现接口 :UserDaoImpl

package com.kuang.w.demo02.dao;
public class UserDaoImpl implements UserDao {
    public void add() {
        System.out.println ("添加....");
    }
    public void upTable() {
        System.out.println ("删除....");
    }
}

service层
1-2-0 接口UserService

package com.kuang.w.demo02.service;
public interface UserService {
    /**
     * class add()
     */
    void add();
    /**
     * class upsate
     */
    void update();
}

1-2-1实现接口 UserServiceImpl

package com.kuang.w.demo02.service;

import com.kuang.w.demo02.dao.UserDao;
import com.kuang.w.demo02.dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl ();
    public void add() {
        userDao.add ();
    }
    public void update() {
        userDao.upTable ();
    }
}

1-2-2实现接口 UserServiceImpl
这是一个增强功能 的实现接口 添加了一个日志功能

package com.kuang.w.demo02.service;

import com.kuang.w.demo02.dao.UserDao;

import java.lang.reflect.InvocationHandler;
public class UserServiceImplLog implements UserDao {
    private UserServiceImpl userService = new UserServiceImpl ();

    public void add() {
        userService.add ();
        log ("add");
    }

    public void upTable() {
        userService.update ();
        log ("up");
    }
    public void log(String name) {
        System.out.println (" 调用了" + name + "方法!");
    }
}

3测试:

 public void t07() {
        UserServiceImplLog implLog = new UserServiceImplLog ();
        implLog.upTable ();
    }

测试结果:

删除....
 调用了up方法!
Process finished with exit code 0

动态代理(固定代码)

package com.kuang.w.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 动态代理 :用这个类自动生成代理类
 */
public class ProxyInvocationHandlerUtil implements InvocationHandler {
    /**
     * 被代理的接口
     * Object target
     */
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    /**
     * 生成代理类
     */
    public Object getProxy() {
        return Proxy.newProxyInstance (this.getClass ().getClassLoader (), target.getClass ().getInterfaces (), this);
    }
    /**
     * 处理代理实例 并返回结果
     * 执行被代理类的方法
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke (target, args);
        log (method.getName ());
        return invoke;
    }
//这是一个添加的方法
    private void log(String msg) {
        System.out.println ("调用了" + msg + "方法");
    }
}

测试:(引用了前面包在这里插入代码片内的方法)

package com.kuang.w.demo03;

import com.kuang.w.demo02.service.UserService;
import com.kuang.w.demo02.service.UserServiceImpl;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;

import javax.annotation.Resource;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl ();

        //代理角色不存在  就创建
        ProxyInvocationHandlerUtil pih = new ProxyInvocationHandlerUtil ();

        //设置要代理的对象
        pih.setTarget (userService);
        //动态生成代理
        UserService proxy = (UserService) pih.getProxy ();
        proxy.update ();
    }
}

使用spring方式 重点

AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

一 AOP的基本概念

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

二 Spring AOP

Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。
spring入门3-AOPmaven配置加上:

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

方式一 使用原生的 spring API接口

package com.kuang.w.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
public class MyLog01 implements MethodBeforeAdvice {
    /**
     * method 要执行的的目标对象的方法
     * objects --- args 参数
     * o --- target 目标对象
     */
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println (o.getClass ().getName () + "的" + method.getName () + "方法被执行了!");
    }
}

第一种 beans.xml配置

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--
    bean标签 id唯一标识符 也就相当于我们 学的对象
    class 对应对象的全限定名 包名 + 类型
    name 也是别名 而且name 可以取多个别名  可以用 , ; 空格分隔
    -->
    <!--注册bean-->
    <bean class="com.kuang.w.service.UserServiceImpl" id="userService"/>
    <bean class="com.kuang.w.log.MyLog01" id="myLog"/>
     <!--方式一 使用原生的 spring API接口-->
     <!--绑定log  配置aop -->
     <aop:config>
         <!--切入点:execution:表达式 execution(要执行的位置! 修饰词 返回值 类名 方法名 参数)-->
         <aop:pointcut id="poi" expression="execution(* com.kuang.w.service.UserServiceImpl.*(..))"/>
         <!--执行环绕-->
         <aop:advisor advice-ref="myLog" pointcut-ref="poi"/>
     </aop:config>
</beans>

测试(3个代码都一样):

 @Test
    public void Test08() {
        ApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml");
        UserService userService = context.getBean ("userService", UserService.class);
        userService.update ();
    }
}

测试结果:

com.kuang.w.service.UserServiceImpl的update方法被执行了!
修改方法

第二种方式 自定义( 推荐)

package com.kuang.w.log;
public class Log2 {
    public void qw() {
        System.out.println ("执行前");
    }
    public void hw() {
        System.out.println ("执行后");
    }
}

第二种 beans.xml配置

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--
    bean标签 id唯一标识符 也就相当于我们 学的对象
    class 对应对象的全限定名 包名 + 类型
    name 也是别名 而且name 可以取多个别名  可以用 , ; 空格分隔
    -->
    <!--注册bean-->
    <bean class="com.kuang.w.service.UserServiceImpl" id="userService"/>
    <bean class="com.kuang.w.log.MyLog01" id="myLog"/>
    <bean class="com.kuang.w.log.Log2" id="log2"/>
    <!-- 推荐-->
        <!--第二种方式 自定义-->
        <aop:config>
            <!--自定义 切面-->
            <aop:aspect ref="log2">
                <!--切入点-->
                <aop:pointcut id="poi" expression="execution(* com.kuang.w.service.UserServiceImpl.*(..))"/>
                <aop:before method="qw" pointcut-ref="poi"/>
                <aop:after method="hw" pointcut-ref="poi"/>
            </aop:aspect>
        </aop:config>
</beans>

测试结果:

执行前
修改方法
执行后
Process finished with exit code 

第三种 java代码

package com.kuang.w.log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Log03 {
    /**
     * @Before 执行方法前
     */
    @Before("execution(* com.kuang.w.service.UserServiceImpl.*(..))")
    public void before01() {
        System.out.println ("执行前===");
    }
    /**
     * @After 执行方法后
     */
    @After("execution(* com.kuang.w.service.UserServiceImpl.*(..))")
    public void after() {
        System.out.println ("执行后====");
    }

    /**
     * 环绕注解 在一个方法执行时
     *
     * @Around
     */
    @Around("execution(* com.kuang.w.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint joinPoint) {
        System.out.println ("方法执行前");
        try {
            Object proceed = joinPoint.proceed ();
        } catch (Throwable throwable) {
            throwable.printStackTrace ();
        }
        //获取签名
        System.out.println ("调用了:" + joinPoint.getSignature () + "的方法,执行了");
        System.out.println ("方法执行后");
    }
}

第三种 beans.xml配置

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--
    bean标签 id唯一标识符 也就相当于我们 学的对象
    class 对应对象的全限定名 包名 + 类型
    name 也是别名 而且name 可以取多个别名  可以用 , ; 空格分隔
    -->
    <!--注册bean-->
    <bean class="com.kuang.w.service.UserServiceImpl" id="userService"/>
    <bean class="com.kuang.w.log.MyLog01" id="myLog"/>
  
     <!--第三种 注解-->
    <!--还是用bean注册-->
    <bean class="com.kuang.w.log.Log03" id="log03"/>
    <!--开启注解支持  实现方式:jdk(默认 expose-proxy="false") cglib(expose-proxy="true")-->
    <aop:aspectj-autoproxy expose-proxy="true"/>
</beans>

测试:

 @Test
    public void Test08() {
        ApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml");
        UserService userService = context.getBean ("userService", UserService.class);
        userService.update ();
    }
}

测试 第三种结果

方法执行前
执行前===
修改方法
执行后====
调用了:void com.kuang.w.service.UserService.update()的方法,执行了
方法执行后
Process finished with exit code 0
上一篇:springboot yaml配置注入


下一篇:SSM-Spring整合Mybatis