当前位置 博文首页 > 空手道丶大师兄的博客:IOC控制反转和AOP面向切面化编程

    空手道丶大师兄的博客:IOC控制反转和AOP面向切面化编程

    作者:[db:作者] 时间:2021-07-18 22:21

    IOC控制反转和AOP面向切面化编程

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

    Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。

    IoC推导 (为什么用IoC)

    ####原本编程方法

    1、先写一个UserDao接口

    public interface UserDao {
       public void getUser();
    }
    

    2、再去写Dao的实现类

    public class UserDaoImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("获取用户数据");
      }
    }
    

    3、然后去写UserService的接口

    public interface UserService {
       public void getUser();
    }
    

    4、最后写Service的实现类

    public class UserServiceImpl implements UserService {
       private UserDao userDao = new UserDaoImpl();
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }
    

    5、测试一下

    @Test
    public void test(){
       UserService service = new UserServiceImpl();
       service.getUser();
    }
    

    这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .

    把Userdao的实现类增加一个 .

    public class UserDaoMySqlImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("MySql获取用户数据");
      }
    }
    

    紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现

    public class UserServiceImpl implements UserService {
       private UserDao userDao = new UserDaoMySqlImpl();
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }
    

    在假设, 我们再增加一个Userdao的实现类 .

    public class UserDaoOracleImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("Oracle获取用户数据");
      }
    }
    

    那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .

    改进方法我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .

    public class UserServiceImpl implements UserService {
       private UserDao userDao;
    // 利用set实现
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
      }
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }
    

    现在去我们的测试类里 , 进行测试 ;

    @Test
    public void test(){
       UserServiceImpl service = new UserServiceImpl();
       service.setUserDao( new UserDaoMySqlImpl() );
       service.getUser();
       //那我们现在又想用Oracle去实现呢
       service.setUserDao( new UserDaoOracleImpl() );
       service.getUser();
    }
    

    大家发现了区别没有 ? 可能很多人说没啥区别 . 但是同学们 , 他们已经发生了根本性的变化 , 很多地方都不一样了 . 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .

    这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

    IoC本质

    控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

    IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

    Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

    采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

    控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

    AOP面向切面编程

    https://www.cnblogs.com/demoMeng/p/5881473.html

    一、SpringAOP

    ⒈AOP:Aspect Oriented Programming 面向切面编程, 实现的是核心业务和非核心业务之间的的分离,让核心类只做核心业务,代理类只做非核心业务。

    ⒉目的:

    ⑴、把核心业务和非核心业务进行分离

    ? ⑵、把多个非核心业务处理(点)变成一个切面(之前的非核心业务代码需要写多次变成只需要写一次。)

    ⒊要求:只有当核心类中有多个业务需要进行处理的时候使用AOP较为合理,如果只有一个业务需要被处理那么就没有必要使用AOP了。

    二、静态代理

    1、**需要知道核心类(被代理类)是哪一个类,并且有什么方法。 **

    2、非核心的代码需要重复写多次,显得代码的结构臃肿,形成代码冗余。

    3、非核心类(代理类)需要实现核心类(被代理类)实现的接口,也就是他们需要实现共同的接口,但是以核心类实现的接口(被代理类)为准。

    三、动态代理:

    1、不需要知道核心类(被代理类)具体是什么类。

    2、**非核心类(代理类)需要实现InvocationHandler接口。 **

    https://www.cnblogs.com/demoMeng/p/5881473.html

    四、静态代理示例

    1、业务介绍:

    假定高三学生为核心类,学生的家人是代理类。高三学生需要做的核心业务有:在家学习(studyAtHome)、在学校学习(studyAtHome);家人需要做的非核心业务为:准备饭菜(买、洗、炒、煮饭)。准备补品(购买、熬制、加佐料)。

    2、具体代码:

    ⑴、创建一个高三学生的接口:G3Student

    package aop_001;
    
    
    
    //首先定义一个接口,用来高三学生来是实现,
    //在这个接口中声明一个在家学习和一个在学校学习的方法
    
    public interface G3Student {
    
        public void studyAtHome(String core);
        public void studyAtSchool(String core);
        
    }  
    

    ⑵、创建一个高三学生实现类:G3Student_boy,并且这个类实现高三学生接口(G3Student)

    package aop_001;
    
    
    //定义一个高三男孩的类(目标对象、核心对象、target对象),实现了高三学生的接口。
    public class G3Student_boy implements G3Student {
    
        
        //高三男孩 的第一个业务流程:在家学习
        public void studyAtHome(String core) {
    
           //核心的事情在家学习。
            System.out.println(core+"在HOME学习");
            
        }
    
        //高三男孩 的第二个业务流程:在学校学习
        public void studyAtSchool(String core) {
           //核心的事情在家学习。
            System.out.println(core+"在SCHOOOL学习");
            
        }
    
    }    
    

    ⑶、创建一个高三学生的代理类:G3Student_proxy,并且实现了高三学生接口:G3Student。红色字体需要理解

    package aop_001;
    /*
    *    代理对象(G3Student_proxy)的目的是帮助核心对象(G3Student_boy / G3Student_girl)做非核心的事情。
    *    但是代理对象(G3Student_proxy)必须和核心对象(G3Student_boy / G3Student_girl)实现共同的接口。
    */
    public class G3Student_proxy implements G3Student {
    
        
        //定义一个高三学生接口 作为属性,目的是就是在处理完代理需要做的事情之后调用高三男孩或者是高三女孩需要做的核心业务,
        //但是不是代理具体去做这些核心的事情,只是调用它们而已。    
        private G3Student G3S;
        
        
        //创建一个代理的参数为 高三学生接口 的构造函数,判断但传入的字符串为boy就构造一个高三男孩的实例,如果传入的参数为girl就构造一个高三女孩的实例。
        public G3Student_proxy(String sex) {
            if("boy".equals(sex)){
                G3S = new G3Student_boy();
            }else if("girl".equals(sex)){
                G3S = new G3Student_girl();
            }        
        }
    
        public void studyAtHome(String core){
        
            //这个是代理(G3Student_proxy)准备饭菜的需要做的流程:    
            System.out.println("代理:准备买菜");
            System.out.println("代理:准备洗菜");
            System.out.println("代理:准备炒菜");
            System.out.println("代理:准备煮饭");
            System.out.println("-----------------");  
    
            //通过定义的属性,并且在调用G3Student_proxy的含参数的构造函数创建相对应的实例,调用这个具体的实例的方法
            G3S.studyAtHome(core);
    
         //这个是代理(G3Student_proxy)准备补品的需要做的流程:
            System.out.println("-----------------");
            System.out.println("代理 :购买补品");
            System.out.println("代理 :熬制部品");
            System.out.println("代理 :加入佐料");
            System.out.println();
     
        }
        
        public void studyAtSchool(String core) {
    
            //这个是代理准备(G3Student_proxy)饭菜的需要做的流程:    
            System.out.println("代理:准备买菜");
            System.out.println("代理:准备洗菜");
            System.out.println("代理:准备炒菜");
            System.out.println("代理:准备煮饭");
            System.out.println("-----------------");
            
            //通过定义的属性,并且在调用G3Student_proxy的含参数的构造函数创建相对应的实例,调用这个具体的实例的方法
            G3S.studyAtSchool(core);
      
            System.out.println("-----------------");
            //这个是代理(G3Student_proxy)准备补品的需要做的流程:
            System.out.println("代理 :购买补品");
            System.out.println("代理 :熬制部品");
            System.out.println("代理 :加入佐料");
            System.out.println(
    
    下一篇:没有了