框架基础(5) : 手把手实现的个完整的AOP

上一章讲了通过动态代理实现了一个AOP,只是一个了解一下概念,那么我们实现一个简单的框架的AOP。那么我们来个复杂的代理;用到了工厂模式、文件读取、JavaBan、动态代理、内省等知识。如果这些还不明白的话去看一下我的前面写的教程。
需求:我们的用户管理时都要记录开始日志与结束日志
1.创建一个类

public class User{
    
    
    private String name;
    private String pwd;

    public User() {
    
    
    }

    public User(String name, String pwd) {
    
    
        this.name = name;
        this.pwd = pwd;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getPwd() {
    
    
        return pwd;
    }

    public void setPwd(String pwd) {
    
    
        this.pwd = pwd;
    }
    @Override
    public String toString() {
    
    
        return "User{" +
                "name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

2.定义一个管理接口

public interface Imanger {
    
    
    public void add(User U);
}

3.用一个类管理这个接口,将来也是被代理对象

public class UserManger implements Imanger {
    
    
    private List<User> list=new ArrayList<>();
    @Override
    public void add(User U) {
    
    
        System.out.println("-----正式操作--添加用户");
        list.add(U);
        System.out.println("添加成功:"+U.toString());
    }
}

4.写个切面接口

public interface Advice {
    
    
    public void Startadvice();
    public void endadvice();
}

5.写一个切面实现类 代来是这个是切面层

package com;
//---------------AOP 这个是切面层
public class LogAdvice implements Advice{
    
    

    @Override
    public void Startadvice() {
    
    
        System.out.println("---开始记录日志----");
    }

    @Override
    public void endadvice() {
    
    
        System.out.println("---业务操作结束------");
    }
}

6.代理工厂利用Bean 实现代理方法

package com;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//---代理工厂利用Bean 实现代理方法
public class ProxyFactoryBean implements InvocationHandler {
    
    
    private Object target;
    private Advice advice;

    //获取代理对象
    public Object getProxy(){
    
    
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
    
    
        advice.Startadvice();
        Object res=null;
        res=method.invoke(target,objects);
        advice.endadvice();
        return res;
    }

    public Object getTarget() {
    
    
        return target;
    }

    public void setTarget(Object target) {
    
    
        this.target = target;
    }

    public Advice getAdvice() {
    
    
        return advice;
    }

    public void setAdvice(Advice advice) {
    
    
        this.advice = advice;
    }
}

7.配置一个文件 用于读取组装信息

bean=com.ProxyFactoryBean
bean.target=com.UserManger
bean.advice=com.LogAdvice

8.创建组装工厂(这部分用到了内省,不懂的可以[点这里] 我这里没有用try语块而是通过throw方式,目的是为了让大家更容易阅读。(https://blog.csdn.net/weixin_44690195/article/details/106710618))

package com;

import aop.Advice;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class BeanFactory {
    
    
    Properties prop=new Properties();//流容器
    public BeanFactory(InputStream in){
    
    
        try {
    
    
            prop.load(in);//载入流
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
    public Object getBean(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IntrospectionException, InvocationTargetException {
    
    
        String classname = prop.getProperty(name);//获取代理名称
        Object bean = null;//代理中心

        Class<?> aClass = Class.forName(classname);//装载类
        bean = aClass.newInstance();//把类实例化

        Object target = Class.forName(prop.getProperty(name + ".target")).newInstance();//装载被代理并实例化(注意一定要实例化)
        Object advice = Class.forName(prop.getProperty(name + ".advice")).newInstance();//同上

        BeanInfo beanInfo = Introspector.getBeanInfo(aClass);//把类反射

        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();//获取全部成员
        //遍历成员
        for(PropertyDescriptor pb:propertyDescriptors){
    
    
            String propertyname=pb.getName();//获取成员名称

            Method writeMethod = pb.getWriteMethod();//打开Set开关
            if ("target".equals(propertyname)){
    
    
                writeMethod.invoke(bean,target);//把对像写入
            } else if ("advice".equals(propertyname)){
    
    
                writeMethod.invoke(bean,advice);//同上
            }
        }
        return bean;
    }
}

9.测试成果

		InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/bean.properties");
        BeanFactory bf=new BeanFactory(in);
        ProxyFactoryBean proxyFactorybean = (ProxyFactoryBean)bf.getBean("bean");
        Imanger proxy =(Imanger) proxyFactorybean.getProxy();
        proxy.add(new User ("Admin","password"));

效果

---开始记录日志----
-----正式操作--添加用户
添加成功:User{
    
    name='Admin', pwd='password'}
---业务操作结束------

总结
这里对于新手来说有很多难理解的东西,可能会因一句代码就会让程序跑不出来。所以一定要自己写一次。

猜你喜欢

转载自blog.csdn.net/weixin_44690195/article/details/106718645