JAVAEE框架整合技术之Spring02-AOP面向切面编程技术

Posted teayear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVAEE框架整合技术之Spring02-AOP面向切面编程技术相关的知识,希望对你有一定的参考价值。

Spring新注解

Spring5.0之后的注解称为新注解

使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置

注解说明
@Configuration表示当前类是一个配置类,用于代替配置文件,相当于applicationContext.xml
@Bean作用于方法上,用于将方法的返回值存入spring容器中
@ComponentScan用于指定扫描包路径
Value:用于指定路径 数组basePackages:和value一样
相当于 <context:component-scan base-package=“”/>

@Configuration

spring-new-annotation

/**
 *   @Configuration 相当于 applicationContext.xml配置文件
 *   @ComponentScan 相当于 <context:component-scan base-package="cn.yanqi"/>
 *   @Bean("person")相当于 <bean id="person" class="cn.yanqi.pojo.person"/>
 */
@Configuration
@ComponentScan(basePackages = "cn.yanqi")
public class SpringConfiguration 
    @Bean("person")
    public Person person()
        return new Person();
    

@Data
public class Person 
    @Value("11")
    private int id;
    @Value("jack")
    private String name;
    @Value("男")
    private String sex;
public class UserServiceTest     
    @Test
    public void login() 
        //注意所使用对象:new AnnotationConfigApplicationContext(SpringConfiguration.class);
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);

        Person person = applicationContext.getBean("person", Person.class);
        System.out.println(person);
    

@Bean

@Bean注入对象

/**
 * @Auther: yanqi
 * @Desc    @Configuration 相当于 applicationContext.xml配置文件
 *          @ComponentScan 相当于 <context:component-scan base-package="cn.yanqi"/>
 *          @Bean("person") 相当于 <bean id="person" class="cn.yanqi.pojo.person"/>
 */

@Configuration
@ComponentScan(basePackages = "cn.yanqi")
public class SpringConfiguration 
    @Bean("userService")
    public UserService userService()
        //注入dao层对象
        return new UserServiceImpl(userDao());
    
    @Bean("userDao")
    public UserDao userDao()
        return new UserDaoImpl();
    

public class UserServiceImpl implements UserService 

    private UserDao userDao;
    //提供UserServiceImpl有参构造
    public UserServiceImpl(UserDao userDao) 
        this.userDao = userDao;
    

    @Override
    public void login() 
        System.out.println("业务层 登录!!!");
        userDao.login();
    

/**
 * @Auther: yanqi
 * @Date: 18:35
 * @Desc
 */
public class UserDaoImpl implements UserDao 
    @Override
    public void login() 
        System.out.println("dao层登录成功!!!");
    


    @Test
    public void login() 
        //注意所使用对象:new AnnotationConfigApplicationContext(SpringConfiguration.class);
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);

        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();
    

@Component

纯注解开发

/**
 * 
 *     	    @Configuration 相当于 applicationContext.xml配置文件
 *          @ComponentScan 相当于 <context:component-scan base-package="cn.yanqi"/>
 *          @Bean("person")相当于 <bean id="person" class="cn.yanqi.pojo.person"/>
 */
@Configuration
@ComponentScan(basePackages = "cn.yanqi")
public class SpringConfiguration 

@Service("userService")
public class UserServiceImpl implements UserService 
    @Autowired
    private UserDao userDao;

    @Override
    public void login() 
        System.out.println("业务层 登录!!!");
        userDao.login();
    

@Repository("userDao")
public class UserDaoImpl implements UserDao 
    @Override
    public void login() 
        System.out.println("dao层登录成功!!!");
    

public class UserServiceTest 
    
    @Test
    public void login() 
        //注意所使用对象:new AnnotationConfigApplicationContext(SpringConfiguration.class);
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);

        Person person = applicationContext.getBean("person", Person.class);
        System.out.println(person);
    

@PropertySource

@PropertySouce是spring3.1开始引入的基于java config的注解。

通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。

@Configuration
@PropertySource("classpath:jdbc.properties")
public class PropertiesWithJavaConfig 
   @Value($jdbc.driver)
   private String driver;
   @Value($jdbc.url)
   private String url;
   @Value($jdbc.username)
   private String username;
   @Value($jdbc.password)
   private String password;
   //要想使用@Value 用$占位符注入属性,这个bean是必须的,这个就是占位bean,另一种方式是不用value直接用Envirment变量直接getProperty('key')  
   @Bean
   public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() 
      return new PropertySourcesPlaceholderConfigurer();
   

动态代理

什么是代理

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

代理的核心角色

  • 抽象角色(接口类)

    定义代理角色和真实角色公共对外的方法

  • 真实角色(实现类)

    实现抽象角色,定义真实角色所要实现的业务逻辑,让代理角色调用

    真实角色-关注的是真正的业务逻辑

  • 代理角色(代理实现的类,最终使用的对象)

    实现抽象角色,是真实角色的代理,通过真实角色 的业务逻辑方法来实现抽象方法,并可以附加 自己的操作

    将统一的流程控制放到代理角色中处理

代理的应用场景

  • 可以在不修改别代理对象代码的基础上,通过扩展代理类,进行一些功能的附加与增强
    这样我们就屏蔽了对真实角色的直接访问
  • Spring的AOP机制就是采用动态代理的机制来实现切面编程

代理的分类

  • 静态代理

    需要我们手动定义静态代理类对象

    1. 目标角色固定
    2. 在应用程序执行前就得到目标角色
    3. 代理对象会增强目标对象的行为
    4. 有可能存在多个代理,引起"类爆炸"(缺点)
  • 动态代理

    • JDK 代理 : 基于接口的动态代理技术
    • cglib 代理:基于父类的动态代理技术

静态代理代码实现

  • 定义接口
package cn.yanqi.proxy;
// 抽象角色
public interface Star 
    /**      唱歌     */
    public void sing();
    /**   订票     */
    public void tickets();
    /** 签合同     */
    public void contract();

  • 真实对象
// 真实对象
public class RealStar implements Star 
    public void sing() 
        System.out.println("RealStar.sing.....");
    
    public void tickets() 
        System.out.println("RealStar.tickets.....");
    
    public void contract() 
        System.out.println("RealStar.contract.....");
    

  • 代理对象
package cn.yanqi.proxy;
//代理对象
public class ProxyStar implements Star 
    private RealStar realStar;
    public ProxyStar(RealStar realStar) 
        this.realStar = realStar;
    
    public void sing() 
        // 调用真实对象的唱歌功能
        realStar.sing();
    
    public void tickets() 
        System.out.println("ProxyStar.tickets....");
    
    public void contract() 
        System.out.println("ProxyStar.contract....");
    

  • 测试
public class Test 
    public static void main(String[] args)         
        RealStar realStar = new RealStar();
        ProxyStar proxyStar = new ProxyStar(realStar);

        proxyStar.tickets();
        proxyStar.contract();
        proxyStar.sing();
    

静态代理对于代理的角色是固定的,如 dao 层有20个 dao 类,如果要对方法的访问权限进行代理,此时需要创建20个静态代理角色,引起类爆炸,无法满足生产上的需要,于是就催生了动态代理的思想。

动态代理代码实现

动态代理的实现有两种,JDK和CGLIB,在这里我们以JDK的方式来演示动态代理

创建出来的代理都是java.lang.reflect.Proxy的子类

  • 定义Star接口
public interface Star 
    /**  唱歌     */
    public String sing(double money);
    /** 订票     */
    public void tickets();
    /** 签合同   */
    public void contract();

  • 定义歌手类
public class RealStar implements Star     
    @Override
    public String sing(double money) 
        System.out.println("真实对象收到:" + money + "元, 准备开始唱歌!");
        return "代理对象说,马上开始唱歌了!";
    

    @Override
    public void tickets() 
        System.out.println("RealStar.tickets.....");
    
    @Override
    public void contract() 
        System.out.println("RealStar.contract.....");
    

  • 创建代理类
package cn.yanqi.proxy;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;
import java.lang.reflect.Method;
public class JDKProxy 
    public static void main(String[] args) 
        //真实对象
        final RealStar realStar = new RealStar();
        /**
         * 创建代理对象
         *  参数一: 真实对象getClass().getClassLoader()
         *  参数二: 真实对象getClass().getInterfaces()
         *  参数三: 处理器new InvocationHandler
         */
        Star proxyObject = (Star) Proxy.newProxyInstance(realStar.getClass().getClassLoader(),
                realStar.getClass().getInterfaces(),new InvocationHandler() 
            /**
             * @param proxy  代理对象 一般不用
             * @param method 代理对象调用的方法,被封装为Method对象
             * @param args   代理对象调用方法时,传递的参数
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
                // 对sing方法进行增强
                if (method.getName().equals("sing")) 
                    // 对象参数进行增强
                    Double money = (Double) args[0];
                    // 代理收取代理费
                    money = money - 5000;

                    Object obj = method.invoke(realStar, money);
                    // 对象返回值进行增强
                    return obj + "开始之前,给大家一个小礼物!";

                 else 
                    // 其他方法,还是执行原有的逻辑
                    Object obj = method.invoke(realStar, args);
                    return obj;
                
            
        );

         //调用真实对象的sing方法
         String sing = proxyObject.sing(10000);
         System.out.println(sing);
    

  • 测试

AOP概述

什么是 AOP

​ AOP 为 Aspect Oriented Programming 的缩写,意思为【面向切面编程】,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP 思想: 基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强 !

AOP 的作用及其优势

1. 在程序运行期间,在不修改源码的情况下对方法进行功能增强
2. 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
3. 减少重复代码,提高开发效率,便于后期维护

AOP 的底层实现

​ 实际上,AOP 的底层是通过动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。

AOP 的动态代理技术

  • JDK 代理 : 基于接口的动态代理技术
  • cglib 代理:基于父类的动态代理技术

AOP相关专业术语

  • 目标对象(target)
目标对象指将要被增强的对象,即包含主业务逻辑的类对象。
  • 连接点(JoinPoint)
程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
连接点由两个信息确定:
	 ==方法(表示程序执行点,即在哪个目标方法)==
	 ==相对点(表示方位,即目标方法的什么位置,比如调用前,后等)==
简单来说,连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。
  • 代理对象(Proxy)
AOP中会通过代理的方式,对目标对象生成一个代理对象,代理对象中会加入需要增强功能,通过代理对象来间接的方式目标对象,起到增强目标对象的效果。
  • 通知/增强(Advice)
需要在目标对象中实现增强的功能
  • 切入点(Pointcut)
	用来指定需要将通知使用到哪些地方,比如需要用在哪些类的哪些方法上,切入点就是做这个配置的。
  • 切面(Aspect)
	通知(Advice)和切入点(Pointcut)的组合。切面来定义在哪些地方(Pointcut)执行什么操作(Advice)。
  • 织入(Weaving)
	把Advice加到Target上,被创建出代理对象的过程

切入点表达式

切点表达式语法

bean(bean Id/bean name) 
execution(* cn.yanqi.spring.CustomerServiceImpl.*(..)) 
execution(* cn.yanqi.spring..*.*(..)) 
  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号*代替,代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
  • 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表

Aop 基于_xml配置

添加依赖

  • 添加aop依赖
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>
<!--aop依赖包在context依赖中已存在-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>
  • 引入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>

实现步骤

第一步:目标(确定)

第二部:通知/增强(编写)

第三步:配置切面 (包括切入点和切面的结合)对哪些方法进行怎么的增强

目标类

/**
 * @Auther: yanqi
 * @Desc 目标类
 */
public interface CustomerService 
    public void save();
    public int findCount();

package cn.yanqi.service;

/**
 * @Auther: yanqi
 * @Desc 目标类
 */
public class CustomerServiceImpl implements CustomerService 
    public void save() 
        System.out.println("业务层:【客户保存了】-----------");
    
    public int findCount() 
        System.out.println("业务层:【客户查询了】-----------");
        return 100;
    


/**
 * @Auther: yanqi
 * @Desc 目标类
 */
public class ProductService 
    public void save()
        System.out.println("业务层:【商品保存了】-----------");
    

    public int findCount() 
        System.out.println("业务层:【查询商品了】-----------");
        return 200;
    


增强类

/**
 * @Auther: yanqi
 * @Desc 配置增强类
 */
public class MyAdvice 
    public void before()
        System.out.println("前置增强了-----------"以上是关于JAVAEE框架整合技术之Spring02-AOP面向切面编程技术的主要内容,如果未能解决你的问题,请参考以下文章

JAVAEE框架整合技术之Spring01-IOC教程

JAVAEE框架整合技术之Spring01-IOC教程

JAVAEE框架整合技术之spring03-SpringJdbcTemplate模板技术和事务处理

JavaEE开发之Spring框架整合1

JavaEE开发之Spring框架整合2(完结撒花)

JAVAEE框架技术之14SSM综合案例