Aop基础与静态代理动态代理基础

静态代理

角色分析:

  • 抽象角色:一般会使用借口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户:访问代理对象的人

代理模式的好处

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共业务
  • 公共业务就交给代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理

缺点

  • 一个真实角色就会产生一个代理角色;代码量会翻倍~开发效率会变低

穿插知识:面向对象的七大原则

  1. 开放封闭原则:软件实体应该是可扩展的,⽽不可修改的。也就是,对扩展开放,对修改封闭的。

  2. 依赖倒置原则:依赖于抽象。具体⽽⾔就是⾼层模块不依赖于底层模块,⼆者都同依赖于抽象;抽象不依赖于具体,具体依赖于
    抽象。

  3. ⾥⽒替换原则,很严格的原则,规则是“⼦类必须能够替换基类,否则不应当设计为其⼦类。”也就是说,⼦类只能去扩展基
    类,⽽不是隐藏或覆盖基类。

  4. 接⼝隔离原则:使⽤多个⼩的专门的接⼝,⽽不要使⽤⼀个⼤的总接⼝

  5. 单⼀职责原则:⼀个类,最好只做⼀件事,只有⼀个引起它的变化。单⼀职责原则可以看做是低耦合、⾼内聚在⾯向对象原则上
    的引申,将职责定义为引起变化的原因,以提⾼内聚性来减少引起变化的原因。

  6. 合成/聚合复⽤原则:应尽量使⽤组合和聚合,⽽不是处处使⽤继承

  7. 迪米特原则:一个对象应当对其他对象有尽可能少的了解,不和陌生人说话,尽量降低类与类之间的耦

动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的类是动态生成的,而不是我们直接写成的!
  • 动态代理分为两大类
    • 基于接口的动态代理 ----- JDK动态代理
    • 基于类的动态代理 ----- cglib
    • Java字节码实现 ----Javasisit

需要了解两个类:proxy: 代理 , InvocationHandler:调用处理程序

InvocationHandler

  • 每个代理实例都有一个关联的调用处理程序。
  • invoke(object proxy,方法 method,object[] args) : 处理代理实例上的方法调用并返回结果。

测试类

public class client {
    public static void main(String[] args) {
        //真实角色
        Host host = new Host();

        //代理角色:现在没有
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //通过调用程序处理角色来处理我们要调用的接口对象
        pih.setRent(host);

        Rent proxy = (Rent) pih.getProxy();

        proxy.rent();

    }
}

动态的得到代理

//等会我们会用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);

    }

    //c处理代理实例,并返回结果(核心)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //动态代理的本质,就是使用反射机制实现
        Object result = method.invoke(rent, args);
        return result;
    }

}


接口

public interface Rent {
    public void rent();
}

房东

public class Host implements Rent, com.tingli.demo3.Rent {

    @Override
    public void rent() {
        System.out.println("房东要出租房子~~");
    }
}

动态代理的好处

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共业务
  • 公共业务就交给代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理
  • 一个动态代理类代理的是一个借口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类

AOP

什么是AOP

  • 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续 ,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型

AOP在Spring中的作用

== 提供声明式事务;允许用户自定义切面 ==

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存事务等…
  • 切面(ASPECT):横切关注点被模块化的特殊对象。即,他是一个类
  • 通知(Advice):切面必须要完成的工作。即,他是类中的一个方法
  • 目标(Target):被通知的对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 切入点(PointCut):切面通知执行的“地点”的定义
  • 连接点(JointPoint):与切入点匹配的执行点

使用Spring实现AOP

【重点】使用AOP植入,需要导入一个依赖包

 
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.9.4version>
        dependency>

方式一:使用Spring的API接口【主要SpringAPI接口实现】

  • 配置xml

    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:c="http://www.springframework.org/schema/c"
           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 = "userService" class="com.tingli.service.UserServiceImpl"/>
        <bean id = "Log" class="com.tingli.Log.Log"/>
        <bean id = "afterLog" class="com.tingli.Log.AfterLog"/>
    
    
        
        <aop:config>
            
            <aop:pointcut id="pointcut" expression="execution(* com.tingli.service.UserServiceImpl.*(..))"/>
    
            
            <aop:advisor advice-ref="Log" pointcut-ref="pointcut"/>
            <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
        aop:config>
    beans>
    
  • 编写Log与AfterLog类

    //Log类
    import org.springframework.aop.MethodBeforeAdvice;
    
    import java.lang.reflect.Method;
    
    public class Log implements MethodBeforeAdvice {
    
        //method:要执行的目标对象方法
        //args:参数
        //target:目标对象
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println(target.getClass().getName() + "的" + method + "被执行了");
        }
    }
    
    //AfterLog类
    import org.springframework.aop.AfterReturningAdvice;
    import org.springframework.aop.MethodBeforeAdvice;
    
    import java.lang.reflect.Method;
    
    public class AfterLog implements AfterReturningAdvice {
    
        //returnValue:返回值
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("执行了" + method.getName() + "方法,返回结果为:" + returnValue);
        }
    }
    
    
    
    
  • 测试

    import com.tingli.service.UserService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyText {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //动态代理代理的是接口
            UserService userService = context.getBean("userService", UserService.class);
    
            userService.add();
    
        }
    }
    
    

方法二:自定义来实现AOP【主要是切面定义】

  • 配置xml

     
        <bean id="diy" class="com.tingli.diy.DiyPointCut"/>
        
        <aop:config>
            
            <aop:aspect ref="diy">
                
                <aop:pointcut id="point" expression="execution(* com.tingli.service.UserServiceImpl.*(..))"/>
                
                <aop:before method="before" pointcut-ref="point"/>
                <aop:after method="after" pointcut-ref="point"/>
            aop:aspect>
        aop:config>
    
  • 编写diy类

    public class DiyPointCut {
    
        public void before(){
            System.out.println("=========方法执行前=========");
        }
        public void after(){
            System.out.println("=========方法执行后=========");
        }
    
    }
    
    
  • 编写测试类

    import com.tingli.service.UserService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyText {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //动态代理代理的是接口
            UserService userService = context.getBean("userService", UserService.class);
    
            userService.add();
    
        }
    }
    

方法三:使用注解实现

  • 配置xml

        
        <bean id="annotationPointCut" class="com.tingli.diy.AnnotationPointCut"/>
        
        <aop:aspectj-autoproxy/>
    
  • 编写annotationPointCut类(加注解)

    //使用注解方式实现AOP
    
    mport 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 AnnotationPointCut {
    
        @Before("execution(* com.tingli.service.UserServiceImpl.*(..))")
        public void before(){
            System.out.println("========方法执行前========");
        }
        @After("execution(* com.tingli.service.UserServiceImpl.*(..))")
        public void after(){
            System.out.println("========方法执行后========");
        }
    
        //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
        @Around("execution(* com.tingli.service.UserServiceImpl.*(..))")
        public void around(ProceedingJoinPoint jp) throws Throwable {
            System.out.println("环绕前");
    
            //执行方法
            Object proceed = jp.proceed();
    
            System.out.println("环绕后");
        }
    }
    
  • 测试

    import com.tingli.service.UserService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyText {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            //动态代理代理的是接口
            UserService userService = context.getBean("userService", UserService.class);
    
            userService.add();
    
        }
    }
    
    

你可能感兴趣的:(代理模式,java,开发语言)