Understand the configurable AOP framework

I. what is AOP(Aspect Oriented Programming)

  1. Aspect oriented programming: AOP is the complement and perfection of OOP(Object Oriented Programming). It uses a technology called "crosscutting" to dissect the inner part of the packed object, encapsulate the common behaviors that affect multiple classes into a reusable module, and name it "aspect", that is, aspect. The so-called "aspect" is simply the logic or responsibility that has nothing to do with the business but is called by the business modules together. It is convenient to reduce the repeated code of the system, reduce the coupling degree between the modules, and is conducive to the operability and maintainability in the future.
  2. AOP divides the software system into two parts: core concerns and crosscutting concerns. The main process of business processing is the core concern, and the little related part is the crosscutting concern. One of the characteristics of crosscutting concerns is that they often happen in many places of core concerns, and they are basically similar everywhere, such as permission authentication, log, etc. The role of AOP is to separate various concerns in the system and separate the core concerns from the crosscutting concerns.

II. Use scenarios

AOP is used to encapsulate crosscutting concerns, which can be used in the following scenarios: permission, cache, error handling, debugging, record tracking, persistence, synchronization, transaction, etc.

As shown in the figure

III. implementation of handwritten AOP framework

demand

It is known that there is a function module for adding entries. You need to add time logs before and after the implementation of adding entries. Please use the AOP idea to achieve this.

The prototype of AOP is dynamic agent pattern

concrete class

  • BeanFactory: Bean factory, used to create objects (reflections) through configuration
  • ProxyFactoryBean: proxy factory class, used to dynamically generate proxy objects and implement log crosscutting.
  • LogAdvice: log implementation class (Advice log interface)
  • IManagerImpl: add item function implementation class (IManager business interface)
  • bean.properties: used to configure bean, which is convenient for maintenance.

As shown in the figure

code implementation

public class AopTest {
    public static void main(String[] args) {
        // Read profile
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("day11/bean.properties");
        // Create a factory object to generate a Bean
        BeanFactory beanFactory = new BeanFactory(in);
        // Get proxy object create proxy factory through Bean factory
        ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) beanFactory.getBean("bean");
        // Execute business method
        IService proxy = (IService) proxyFactoryBean.getProxy();
        proxy.getMoney();

    }
}
// Service interface
interface IService {
    void getMoney();
}
// Business method
class ServiceImpl implements IService {
    // Business methods focus on the business itself
    @Override
    public void getMoney() {
        System.out.println("A series of core business processes");
    }
}
// Notification (aspect business interface)
interface Advice {
    // Before advice
    void beforeAdvice();
    // Post notification
    void afterAdvice();
}
// Specific implementation of cross cutting business
class LogAdvice implements Advice {
    @Override
    public void beforeAdvice() {
        System.out.println("start:" + System.currentTimeMillis());
    }
    @Override
    public void afterAdvice() {
        System.out.println("end:" + System.currentTimeMillis());
    }
}
// Factory class that generates dynamic proxy objects
class ProxyFactoryBean implements InvocationHandler {
    // Target object of agent
    private Object target;
    // Services to be injected on the agent target
    private Advice advice;
    // How to generate dynamic agents
    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[] args) throws Throwable {
        advice.beforeAdvice();
        // Calling core business methods in a reflective way
        Object obj = method.invoke(target, args);
        advice.afterAdvice();
        return obj;
    }
    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;
    }
}
// Bean factories are used to create objects through configuration
class BeanFactory {
    // Tool class for operating the properties file
    Properties prop = new Properties();
    public BeanFactory(InputStream in) {
        try {
            // Read properties from input byte stream
            prop.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // Generate instance object of Bean
    public Object getBean(String name) {
        // Search for properties using the key specified in this property list
        String className = prop.getProperty(name);
        // Return value of method
        Object bean = null;
        // Using reflection to create a class object with the string name of a class
        try {
            // Returns the Class object associated with a Class or interface with the given string name
            Class<?> aClass = Class.forName(className);
            // Create a new instance of the Class represented by this Class object
            bean = aClass.newInstance();
            // Assembling values for an object's properties
            Object target = Class.forName(prop.getProperty(name + ".target")).newInstance();
            Object advice = Class.forName(prop.getProperty(name + ".advice")).newInstance();
            // Through introspection, the two attributes of ProxyFactoryBean, target and advice, are assigned
            BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
            //Get the property descriptor of the current class through the class information
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor pd : propertyDescriptors) {
                // Get the name of the property
                String propertyName = pd.getName();
                // Get the set method corresponding to the property
                Method writeMethod = pd.getWriteMethod();
                if ("target".equals(propertyName)) {
                    writeMethod.invoke(bean, target);
                } else if ("advice".equals(propertyName)) {
                    writeMethod.invoke(bean, advice);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return bean;
    }
}

The configuration file is as follows

bean.properties

Tags: Programming

Posted on Thu, 07 Nov 2019 23:02:13 -0800 by martian2k4