zoukankan      html  css  js  c++  java
  • Spring IOC与AOP的简单实现

    IOC

    XML方式

    1. 将Spring的核心依赖包全部通过maven导入
    <!--    spring-core spring-beans spring-context spring-expression-->
    <!--    这几个包的版本必须一致-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-expression</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aspects</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
      </dependencies>
    
    1. 在resources文件夹下创建一个Spring config文件
      在这里插入图片描述
    2. 在java文件夹下面创建一个MVC的基本架构(domain、persistence、service、注意test是用来做单元检测的)
      在这里插入图片描述
      其中Account、AccountDAOImpl、AccountService的代码如下:
    public class Account {
    
        private String userName;
    
        private String password;
    
        private int age;
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public Account(String userName, String password, int age) {
            this.userName = userName;
            this.password = password;
            this.age = age;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
    
    }
    
    public class AccountDAOImpl implements  AccountDAO {
        @Override
        public void insert() {
            System.out.println("新增用户");
        }
    
        @Override
        public void deletd() {
            System.out.println("删除用户");
        }
    
        @Override
        public void update() {
            System.out.println("更新用户");
        }
    
        @Override
        public void select() {
            System.out.println("查询用户");
        }
    }
    
    public class AccountService {
    
        private AccountDAO accountDAO;
    
        public AccountService(AccountDAO accountDAO) {
            this.accountDAO = accountDAO;
        }
    
        public void login(){
            System.out.println("Service的login方法");
            accountDAO.select();
        }
    
        public AccountDAO getAccountDAO() {
            return accountDAO;
        }
    
        public void setAccountDAO(AccountDAO accountDAO) {
            this.accountDAO = accountDAO;
        }
    }
    
    1. 根据Account、AccountDAOImpl、AccountService的调用关系(例如Service调用Dao层来实现Account的查询等操作),配置相应的Spring config文件,实现IOC的XML注入方式,注意这里有两种注入方式,一种是构造函数注入,一种是属性注入。
      属性注入:
    <!--     传统的配置注入方式 -->
            <bean id="accountDao" class="org.csu.spring.demo.ioc.persistence.AccountDAOImpl"/>
            <bean id="account" class="org.csu.spring.demo.ioc.demain.Account">
    <!--            <property name="userName" value="John"/>-->
    <!--            <property name="password" value="123456"/>-->
    <!--            <property name="age" value="18"/>-->
            </bean>
            <bean id="accountService" class="org.csu.spring.demo.ioc.service.AccountService">
                <property name="accountDAO" ref="accountDao"/>
            </bean>
    

    构造函数注入:

    <!--     传统的配置注入方式 -->
            <bean id="accountDao" class="org.csu.spring.demo.ioc.persistence.AccountDAOImpl"/>
            <bean id="account" class="org.csu.spring.demo.ioc.demain.Account">
                <constructor-arg name="userName" value="John"/>
                <constructor-arg name="password" value="666666"/>
                <constructor-arg name="age" value="18"/>
            </bean>
            <bean id="accountService" class="org.csu.spring.demo.ioc.service.AccountService">
                <constructor-arg name="accountDAO" ref="accountDao"/>
            </bean>
    
    1. 在test文件夹下创建一个demo单元测试单元,进行测试
    public class demo {
    
        private AccountService service;
    
        @Test
        public  void test(){
            //使用Spring Ioc容器来获取对象
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            Account temp = (Account)context.getBean("account") ;
            AccountService service = (AccountService)context.getBean("accountService");
            service.login();
            System.out.println(temp.getUserName() + "," + temp.getPassword() + "," + String.valueOf(temp.getAge()));
    
        }
    
    }
    

    测试结果如下:
    在这里插入图片描述
    6. 总结
    此方法为Spring IOC实现的基础方法-基于XML配置文件实现的。这样的方法虽然可以实现IOC控制反转,但是有明显的不足。如果有一百个类似的MVC结构的类关系,难道你需要在配置文件配置一百次吗?显然这个是不人性化的,所以接下来介绍注解方式实现IOC。

    注解方式

    注意:前面的1、2、3步和基于XML配置文件实现IOC的步骤一模一样,这里直接从第四步开始!

    1. 将之前的Spring conf配置文件的bean全部删掉,加上下面这一个语句,注释功能实现的基础就是这个包扫描语句
    <!--     开启注解的包扫描-->
        <context:component-scan base-package="org.csu.spring.demo.ioc"/>
    
    1. 在MVC框架中的各个类里面加上相应的注释

    @Component(“name”)用于实体类的声明

    @Component("account")
    public class Account {
        @Value("Mike")
        private String userName;
        @Value("888888")
        private String password;
        @Value("22")
        private int age;
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
        
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
    
    }
    

    @Repository(“name”)用于Dao类的声明

    @Repository("accountDao")
    public class AccountDAOImpl implements  AccountDAO {
        @Override
        public void insert() {
            System.out.println("新增用户");
        }
    
        @Override
        public void deletd() {
            System.out.println("删除用户");
        }
    
        @Override
        public void update() {
            System.out.println("更新用户");
        }
    
        @Override
        public void select() {
            System.out.println("查询用户");
        }
    }
    

    @Service(“name”)用于业务类的声明

    @Service("accountService")
    public class AccountService {
    
        //这个注解它会扫描ioc包的内容,根据类型匹配来注入,如果找不到,会注入null值
        @Autowired
        //按名称去制定
        @Resource(name = "accountDao")
        private AccountDAO accountDAO;
    
        public AccountService(AccountDAO accountDAO) {
            this.accountDAO = accountDAO;
        }
    
        public void login(){
            System.out.println("Service的login方法");
            accountDAO.select();
        }
    
        public AccountDAO getAccountDAO() {
            return accountDAO;
        }
    
        public void setAccountDAO(AccountDAO accountDAO) {
            this.accountDAO = accountDAO;
        }
    }
    

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(“classpath:applicationContext.xml”)
    代表JUnit在相应的环境下进行测试

    //用Junit创建环境
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class demo {
    
        @Autowired
        private AccountService service;
    
    
        @Test
        public  void test(){
            service.login();
        }
    
    }
    
    1. 运行demo1的单元测试,结果如下
      在这里插入图片描述
    2. 总结
      注解的方式只是减少了程序员编码的工作,其中的原理和之前介绍的用配置XML方式实现IOC注入的原理是一模一样的

    AOP

    传统Spring AOP

    动态代理代理类实现

    1. 建立如下的目录结构(aspectj在后面会介绍,这里暂时不用)
      在这里插入图片描述
    2. 相应类的代码
      AccountDao与AccountImpl两个类和之前IOC里面的一模一样,直接拷贝即可。
    public class proxyDemo implements InvocationHandler {
    
        private Object object;
    
        public proxyDemo(Object object) {
            this.object = object;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if(method.getName().equals("select"))
            beforeAdvice();
            Object proxyObject = method.invoke(object,args);
            return proxyObject;
        }
    
        public void beforeAdvice(){
            System.out.println("前置建议:日志记录。。。");
        }
    }
    
    public class demo {
    
    //    @Autowired
    //    private AccountDAO accountDAO;
    
    
        @Test
        public void test(){
    
            AccountDAO accountDao = new AccountDAOImpl();
    
            Class class1 = accountDao.getClass();
    
            accountDao = (AccountDAO)Proxy.newProxyInstance(class1.getClassLoader(),class1.getInterfaces(),new proxyDemo(accountDao));
    
            accountDao.insert();
    
            accountDao.select();
    
        }
    }
    
    1. 运行demo单元测试,结果如下
      在这里插入图片描述
    2. 总结
      传统AOP就是基于InvocationHandler这个接口实现的,其思想和JVM类似。实现AOP的原理如下:通过一个类实现InvocationHandler接口来编写自己的代理类,代理类通过invoke方法实现,对所有被代理类的方法的切入。这个方法有许多不足:所有被代理的类必须是实现接口的类,而且代理类只能实现对于被代理类的方法的切入。

    XML配置实现

    1. 在Resources下面添加新的Spring config文件,并且进行相应的配置(因为需要用到aop的xml命名空间,这里需要在Spring官网里面进行相应的搜索)
      在这里插入图片描述
    2. 新增一个Proxy类,为了和之前的代理类区分
    public class SpringAopProxyDemo implements AfterReturningAdvice {
    
    
        @Override
        public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
            System.out.println("后置意见。。。");
        }
    }
    
    1. 配置Spring config文件
    <?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/context
           https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="accountDAO" class="org.csu.spring.demo.aop.persistence.AccountDAOImpl"/>
    
        <bean id="demoProxy" class="org.csu.spring.demo.aop.proxy.SpringAopProxyDemo"/>
    
        <bean id="demoAfterProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="target" ref="accountDAO"/>
            <property name="interceptorNames" value="demoProxy"/>
            <property name="proxyInterfaces" value="org.csu.spring.demo.aop.persistence.AccountDAO"/>
        </bean>
    </beans>
    
    1. 修改demo测试单元的内容,并且运行得出结果
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext-aop.xml")
    public class demo {
    
        @Resource(name="demoAfterProxy")
        private AccountDAO accountDAO;
    
    
        @Test
        public void test(){
            accountDAO.insert();
    
        }
    }
    

    在这里插入图片描述

    1. 结论
      这个方式和之前的基于动态代理的实现原理一模一样,只不过把硬编码的方式编程类配置文件的方式。

    基于AspectJ的Spring AOP

    1. 修改Spring config的内容
    <?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/context
           https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
        <aop:aspectj-autoproxy/>
        <context:component-scan base-package="org.csu.spring.demo.aop"/>
        <bean id="demoAspect" class="org.csu.spring.demo.aop.persistence.demoAspect"/>
    </beans>
    
    1. 在aspectj文件夹下面创建一个切面类
    @Component
    @Aspect
    public class demoAspect {
    
        //execution(访问修饰符,返回类型,类,方法,参数)
        @Before(value = "execution(* org.csu.spring.demo.aop.persistence.*.*(..))")
        public void before(){
            System.out.println("这是一个前置建议:安全验证。。。");
        }
    }
    
    1. 修改demo测试单元代码,执行得出结果
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext-aop.xml")
    public class demo {
    
        @Autowired
        private AccountDAO accountDAO;
    
    
        @Test
        public void test(){
    
            accountDAO.select();
    
        }
    }
    

    在这里插入图片描述

    1. 结论
      aspectj的思想和之前传统的思想不太一样。动态代理以一个代理类为核心,所以每一个不同的被代理类都需要对应一个代理类,导致过程很繁琐;但是aspectj的核心为切面,每一个切面可以有对应多个被代理类的多个方法,这样的思想可以简化很多代码量!
  • 相关阅读:
    Delphi 中的颜色常量及效果图
    WinAPI: waveInGetErrorText 根据错误号得到错误描述
    WinAPI: waveInGetDevCaps 查询输入设备的性能
    动画演示 Delphi 2007 IDE 功能[2] 定义变量
    动画演示 Delphi 2007 IDE 功能[1] 建立工程、添加控件
    Delphi 的绘图功能[15] 再谈文字的高度与宽度: Canvas.TextExtent
    WinAPI: waveInAddBuffer 向波形输入设备发送一个输入缓冲区
    动画演示 Delphi 2007 IDE 功能[3] 修改属性
    颜色转换函数: 从 Delphi 到 Html
    Spider trap Wikipedia, the free encyclopedia
  • 原文地址:https://www.cnblogs.com/782687539-nanfu/p/12707584.html
Copyright © 2011-2022 走看看