装饰者模式,代理模式,AOP浅析

 

 重写

使用方法

继承,重写

使用场景

主要用于子类覆盖父类的方法

装饰者设计模式模式

如何使用

构造方法中添加要装饰的对象

使用场景

一般应用于增加方法

不改变原来的功能

被装饰的类
class Dog{
    public void eat(){
        System.out.println("狗在吃骨头....");
    }
    
    public void say(){
        System.out.println("狗在汪汪汪的叫...");
    }
}

 

装饰的类
class ZHDog{
    private Dog dog;
    
    public ZHDog(Dog dog){
        this.dog = dog;
    }
    
    public void eat(){
        dog.eat();
    }
    
    public void say(){
        dog.say();
    }
    
    public void drink(){
        System.out.println("狗喝..");
    }
}

 

 

代理设计模式

静态代理模式

优点

可以将功能型代码和业务逻辑分开

缺点

代码的重复并没有解决

接口

接口中包含需要代理的方法

实现接口的类

将代理的方法进行实现(真正需要实现的代码逻辑)

代理类实现

将实现接口的类,进行代理(对代码进行增强)

创建被代理者

对代码进行增强

需要实现的接口: interface MX
interface MX{
    public void sing();
    public void dance();
    public void rap();
    public void ball();
}

 

被代理者:ZJL
class ZJL implements MX{
​
    @Override
    public void sing() {
        System.out.println("周杰伦在唱歌");
    }
​
    @Override
    public void dance() {
        System.out.println("周杰伦在跳舞");
    }
​
    @Override
    public void rap() {
        System.out.println("周杰伦双节棍");
    }
​
    @Override
    public void ball() {
        System.out.println("周杰伦在斗牛");
    }
}

 

代理者:JJR
class JJR implements MX{
    private ZJL zjl = new ZJL();
    @Override
    public void sing() {
        // TODO Auto-generated method stub
        System.out.println("您是谁啊?");
        System.out.println("记录一下");
        zjl.sing();
        System.out.println("结账");
    }
​
    @Override
    public void dance() {
        System.out.println("您是谁啊?");
        System.out.println("记录一下'");
        zjl.dance();
        System.out.println("结账");
    }
​
    @Override
    public void rap() {
        // TODO Auto-generated method stub
        zjl.rap();
    }
​
    @Override
    public void ball() {
        // TODO Auto-generated method stub
        zjl.ball();
    }   
}
 

 

 

动态代理
java基于接口实现

代理者不是自己创建的类,而是被生成的对象

局限性

类中有接口中没有的方法,无法被代理

java动态代理的使用方法

/// 参数一:类加载器  应该和被代理者的加载器相同
/// 参数二:接口的数组  应该和被代理者的接口相同
//  参数三: 回调函数的接口  可以直接使用匿名内部类的形式
        // 当代理者调用接口中的方法时,会先执行到回调函数中
///  回调函数会拦截所有的代理者调用的接口方法
Object proxy = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
            @Override
            //  proxy   代理者
            //  method  代理者的方法
            //  args    代理者的参数列表
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                // TODO Auto-generated method stub
                // 返回方法执行后的返回值
                return null;
            }
        })

 

基于java接口实现(举例)

package com.wiscom.demo;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
​
public class ProxyDemo {
    public static void main(String[] args) {
        // 被代理者
        final CXK kk = new CXK();
        
        MX proxy = (MX) Proxy.newProxyInstance(kk.getClass().getClassLoader(), kk.getClass().getInterfaces(),
                
                new InvocationHandler() {
                    
                    @Override
                    // 参数一:代理者
                    // 参数二:代理者调用的方法
                    // 参数三:代理者调用方法的参数
                    // 返回值就是方法的返回值
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        // TODO Auto-generated method stub
                        System.out.println("方法拦截了吗?");
                        System.out.println(method.getName());
                        System.out.println(Arrays.toString(args));
                        // 调用method方法
                        Object obj = method.invoke(kk, args);// kk.sing(args)  kk.dance(args)
                        return obj;
                    }
                });
        
        // 通过动态代理生成的代理者调用明星的方法
        proxy.sing();
        proxy.dance("");
    }
}
​
​
interface MX{
    public void sing();
    
    public void dance(String name);
}
​
class CXK implements MX{
​
    @Override
    public void sing() {
        System.out.println("wait wait wait");
    }
​
    @Override
    public void dance(String name) {
        System.out.println("跳舞~~~~");
    }
    
    public void eat(){
        System.out.println("吃饭......");
    }
}

 

cglib实现代理

cglib实现动态代理(第三方包)

包在spring-core中已包含

package com.wiscom.demo;
​
import java.lang.reflect.Method;
​
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
​
public class Demo {
    public static void main(String[] args) {
        // 被代理者
        final WYF ff = new WYF();
        // 创建增强器
        Enhancer en = new Enhancer();
        // 可以提供接口  可以设置  可以不设置
//      en.setInterfaces(ff.getClass().getInterfaces());
        // 设置父类
        en.setSuperclass(ff.getClass());
        // 设置回调函数
        en.setCallback(new MethodInterceptor() {
            
            @Override
            // 参数一:代理者 参数二:代理调用的方法  参数三:参数类型
            public Object intercept(Object proxy, Method method, Object[] args,
                    MethodProxy methodProxy) throws Throwable {
                System.out.println(method.getName());
                Object obj;
                if ("rap".equals(method.getName())){
                    obj = method.invoke(ff, args);
                    System.out.println("你们来这里吃面很开心");
                }else{
                    obj = method.invoke(ff, args);
                }
                return obj;
            }
        });
        
        // 获取代理
        WYF proxy = (WYF)en.create();
        // 调用方法
        proxy.rap();
        proxy.dance();
    }
}
​
​
class WYF{
    
    public void rap(){
        System.out.println("你看这个碗又大又圆");
    }
    
    public void dance(){
        System.out.println("跳舞...");
    }
}

 

 

AOP

连接点

controller中调用service中的方法

切入点

切入点=连接点+切入规则

基于切入规则选择出来的连接点

切面

狭义:spring拦截下的切入点

广义:一整套完整的aop代理机制

通知

切面中的方法

目标对象

最终需要调用的真正对象,也就是被代理的对象

 

com.wiscom.aspect.FirstAspect
package com.wiscom.aspect;
​
import org.springframework.stereotype.Component;
​
// 切面类
@Component
public class FirstAspect {
    // 通知
    public void before(){
        System.out.println("开启事务");
        System.out.println("开启日志");
        System.out.println("权限设置");
    }
}

 

applicationContext
<aop:config>
    <!-- 配置切入点 -->
    <aop:pointcut expression="within(com.wiscom.service.UserServletImply)" id="pc01"/>
    <!-- 配置切面 -->
    <aop:aspect ref="firstAspect">
        <!-- 配置通知 -->
        <aop:before method="before" pointcut-ref="pc01"/>
    </aop:aspect>
</aop:config>

 

 

 

posted @ 2020-08-19 15:00  minnersun  阅读(94)  评论(0编辑  收藏  举报