Spring框架学习笔记(四):手动实现 Spring 底层机制(初始化 IOC容器+依赖注入+BeanPostProcessor 机制+AOP)

Spring 整体架构示意图

阶段 -- 编写自己的 Spring 容器,实现多层扫描包

编写自己的 Spring 容器,实现多层扫描包,排除包下不是bean的, 得到 bean 对象,放入到临时ioc容器中

代码实现:

(1)准备代码 创建两个注解ComponentScan.java、Component.java,ComponentScan.java注解用于指定需要扫描的包,Component.java用于标识bean,即加了该注解的类就是bean,没加就不是

package com.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    //表示ComponentScan注解可以传入一个value属性,指定要扫描的包
    String value() default "";
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    //表示Component注解可以传入一个value属性,指定id值
    String value() default "";
}

(2)创建配置类 SpringConfigXml 用来替代xml文件,创建 MonsterService.java、MonsterDao.java用来作为需要放入容器中的bean

import com.spring.annotation.ComponentScan;

/**
 * 这是一个配置类,用来替代xml文件
 */
@ComponentScan(value = "com.spring")
public class SpringConfigXml {
}
import com.spring.annotation.Component;

@Component(value = "monsterDao")
public class MonsterDao {
}
import com.spring.annotation.Component;

/**
 * MonsterService 是一个 Service
 * 1.如果指定value,注入容器时,以指定的value值为准
 * 2.如果没用指定value,则默认为类名首字母小写
 */
@Component(value = "monsterService")//把MonsterService注入到我们自己的spring容器中
public class MonsterService {
}

(3)创建 SpringApplicationContext.java 充当容器类

import com.spring.annotation.Component;
import com.spring.annotation.ComponentScan;
import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 该类作用类似于Spring原生ioc容器
 */
@SuppressWarnings("all")
public class SpringApplicationContext {
    //拿到配置类.class文件
    private Class configClass;
    //ioc存放的就是通过反射创建的对象
    private final ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();

    //构造器
    public SpringApplicationContext(Class configClass) {
        this.configClass = configClass;
//        System.out.println("this.configClass=" + this.configClass);
        //获取要扫描的包
        //1.先获取到ComponentScan注解
        ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        //2.获取到注解的value值
        String path = componentScan.value();
//        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下的所有class文件(在target目录下)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();
        //2.通过类的加载器获取到要扫描的包的资源路径
        path = path.replace(".", "/");//一定要把.替换成/
        URL resource = classLoader.getResource(path);
//        System.out.println(resource);
        //3.将要加载的资源(.class) 路径下的文件进行遍历
        File file = new File(resource.getFile());
        readAllFiles(file, path, classLoader);
    }

    //递归遍历所有包,实现扫描多层包结构
    public void readAllFiles(File file, String path, ClassLoader classLoader) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                if (f.isFile()) {
                    dealFile(f,path,classLoader);
                } else if (f.isDirectory()) {
                    readAllFiles(f, path, classLoader);
                }
            }

        } else if (file.isFile()) {
            dealFile(file,path,classLoader);
        }
    }

    public void dealFile(File f, String path, ClassLoader classLoader){
        //获取到.class文件的绝对路径
        String fileAbsolutePath = f.getAbsolutePath();
        //这里只处理.class文件
        if (fileAbsolutePath.endsWith(".class")) {
            //获取到类全类名
            //1.获取到类名
            String className = fileAbsolutePath.substring
                    (fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//                System.out.println(className);
            //2.拼接成全类名
            String temp = fileAbsolutePath.replace("\\","/");
            String classFullName = temp.substring(temp.indexOf(path),temp.indexOf(".class"));
            classFullName = classFullName.replace("/",".");
//                    System.out.println(classFullName);
            //3.判断该类是不是需要注入容器,看该类是不是有注解 @Component @Service @Repository @Controller
            try {
                //这时,就得到了该类的Class对象
                //1. Class clazz = Class.forName(classFullName) 可以反射加载类
                //2. classLoader.loadClass(classFullName); 也可以反射类的Class
                //3. 区别是 : 上面方式会调用该类的静态方法, 下面方法不会
                //4. aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                Class<?> aClass = classLoader.loadClass(classFullName);
                //判断该类是否有 @Component @Service @Repository @Controller
                if (aClass.isAnnotationPresent(Component.class)) {
                    //org.springframework.util.StringUtils包中的静态方法uncapitalize可以将字符串首字母小写
//                            String keyVal = StringUtils.uncapitalize(className);
                    String keyVal = className.substring(0, 1).toLowerCase() + className.substring(1);
                    //获取到value值,替换指定id
                    if (aClass.isAnnotationPresent(Component.class)) {
                        Component annotation = aClass.getDeclaredAnnotation(Component.class);
                        String value = annotation.value();
                        if (!value.equals("")) {
                            keyVal = value;
                        }
                    }
                    //这时候就可以创建该类的对象,并放入到ioc容器中
                    Class<?> clazz = Class.forName(classFullName);
                    Object o = clazz.newInstance();
                    ioc.put(keyVal, o);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    //通过id获取到bean对象
    public Object getBean(String id){
        return ioc.get(id);
    }
}

阶段 2 -- 将bean信息封装到BeanDefinition对象中,并放入到 Map,初始化单例池

将bean信息封装到BeanDefinition对象中,并放入到 Map,初始化单例池,修改getbean方法,如果是单例返回单例池中的对象,如果是多例则临时创建一个对象

 代码实现:

(1)创建注解 Scope.java 用来标识bean为单例还是多例 ,prototype为多例,singleton为单例

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value(); //不需要给默认值
}

 (2)修改 MonsterService.java ,增加Scope注解,用于测试

@Scope(value = "prototype")
@Component(value = "monsterService")//把MonsterService注入到我们自己的spring容器中
public class MonsterService {
}

(3)BeanDefinition.java,封装bean对象

/**
 * 1. 在扫描时,将 bean 信息,封装到 BeanDefinition 对象中
 * 2. 然后将 BeanDefinition 对象 , 放入到 spring 容器的集合中
*/
public class BeanDefinition {
    private Class clazz;//bean对应的class对象
    private String scope;//bean的作用域,singleton/prototype
}

(4)SpringApplicationContext.java, 将扫描到的 Bean 信息封装到 BeanDefinition 对象中,并保存到 BeanDefinitionMap,实现getBean方法

import com.spring.annotation.Component;
import com.spring.annotation.ComponentScan;
import com.spring.annotation.Scope;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 该类作用类似于Spring原生ioc容器
 */
@SuppressWarnings("all")
public class SpringApplicationContext {
    //拿到配置类.class文件
    private Class configClass;
    //如果对象是单例的,就直接放在这个 单例 bean 对象池
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //将 bean 的定义,放在这个 beanDefinitionMap 集合
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    //构造器
    public SpringApplicationContext(Class configClass) {
        //通过扫描,得到 beanDefinition 的 map
        beanDefinitionsByscan(configClass);
    }

    private void beanDefinitionsByscan(Class configClass) {
        this.configClass = configClass;
//        System.out.println("this.configClass=" + this.configClass);
        //获取要扫描的包
        //1.先获取到ComponentScan注解
        ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        //2.获取到注解的value值
        String path = componentScan.value();
//        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下的所有class文件(在target目录下)
        //1.得到类的加载器
        ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();
        //2.通过类的加载器获取到要扫描的包的资源路径
        path = path.replace(".", "/");//一定要把.替换成/
        URL resource = classLoader.getResource(path);
//        System.out.println(resource);
        //3.将要加载的资源(.class) 路径下的文件进行遍历
        File file = new File(resource.getFile());
        readAllFiles(file, path, classLoader);

        //通过beanDefinitionMap , 初始化singletonObjects 单例池
        //遍历所有的beanDefinition对象
        Enumeration<String> keys = beanDefinitionMap.keys();
        while (keys.hasMoreElements()){
            //得到beanName
            String beanName = keys.nextElement();
            //通过beanName 得到对应的beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //判断该bean是singleton还是prototype
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                //将该bean实例放入到singletonObjects 集合
                Object bean = createBean(beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }

    }

    //递归遍历所有包
    private void readAllFiles(File file, String path, ClassLoader classLoader) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                if (f.isFile()) {
                    dealFile(f,path,classLoader);
                } else if (f.isDirectory()) {
                    readAllFiles(f, path, classLoader);
                }
            }

        } else if (file.isFile()) {
            dealFile(file,path,classLoader);
        }
    }

    private void dealFile(File f, String path, ClassLoader classLoader){
        //获取到.class文件的绝对路径
        String fileAbsolutePath = f.getAbsolutePath();
        //这里只处理.class文件
        if (fileAbsolutePath.endsWith(".class")) {
            //获取到类全类名
            //1.获取到类名
            String className = fileAbsolutePath.substring
                    (fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//                System.out.println(className);
            //2.拼接成全类名
            String temp = fileAbsolutePath.replace("\\","/");
            String classFullName = temp.substring(temp.indexOf(path),temp.indexOf(".class"));
            classFullName = classFullName.replace("/",".");
//                    System.out.println(classFullName);
            //3.判断该类是不是需要注入容器,看该类是不是有注解 @Component @Service @Repository @Controller
            try {
                //这时,就得到了该类的Class对象
                //1. Class clazz = Class.forName(classFullName) 可以反射加载类
                //2. classLoader.loadClass(classFullName); 也可以反射类的Class
                //3. 区别是 : 上面方式会调用该类的静态方法, 下面方法不会
                //4. aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                Class<?> aClass = classLoader.loadClass(classFullName);
                //判断该类是否有 @Component
                if (aClass.isAnnotationPresent(Component.class)) {
                    //org.springframework.util.StringUtils包中的静态方法uncapitalize可以将字符串首字母小写
//                            String keyVal = StringUtils.uncapitalize(className);
                    String keyVal = className.substring(0, 1).toLowerCase() + className.substring(1);
                    //获取到value值,替换指定id
                    Component annotation = aClass.getDeclaredAnnotation(Component.class);
                    String value = annotation.value();
                    if (!value.equals("")) {
                        keyVal = value;
                    }
                    //这时候就可以创建该bean的定义对象
                    Class<?> clazz = Class.forName(classFullName);
                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setClazz(clazz);
                    //如果存在Scope注解,就设置该注解的值,如果不存在,则设为单例 singleton
                    if (clazz.isAnnotationPresent(Scope.class)){
                        Scope s = clazz.getDeclaredAnnotation(Scope.class);
                        String val = s.value();
                        beanDefinition.setScope(val);
                    }else {
                        beanDefinition.setScope("singleton");
                    }
                    //将 BeanDefinition 对象放入 map 集合中
                    beanDefinitionMap.put(keyVal, beanDefinition);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //通过id获取到bean对象
    public Object getBean(String id){
        if (beanDefinitionMap.containsKey(id)) {
            BeanDefinition bean = beanDefinitionMap.get(id);
            String scope = bean.getScope();
            if (scope.equals("singleton")) {
                //如果是单例的,就直接从单例池中获取
                return singletonObjects.get(id);
            } else {
                //如果bean是多实例的,就临时创建一个对象
                Class clazz = bean.getClazz();
                return createBean(bean);
            }
        }else {
            throw new NullPointerException("没有该bean");
        }
    }

    private Object createBean(BeanDefinition bean){
        Class clazz = bean.getClazz();
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

(5)创建主程序,测试

public class AppMain {
    public static void main(String[] args) {
        SpringApplicationContext ioc = new SpringApplicationContext(SpringConfigXml.class);
        MonsterService monsterService = (MonsterService)ioc.getBean("monsterService");
        MonsterService monsterService2 = (MonsterService)ioc.getBean("monsterService");
        MonsterDao monsterDao = (MonsterDao)ioc.getBean("monsterDao");
        MonsterDao monsterDao1 = (MonsterDao)ioc.getBean("monsterDao");
        System.out.println(monsterService);
        System.out.println(monsterService2);
        System.out.println(monsterDao);
        System.out.println(monsterDao1);
        System.out.println("ok~");
    }
}

(6)运行效果

分析:可以看到,多例 bean 每次 getbean 返回的是不同的对象,而单例 bean 每次 getbean 返回的是同一个对象

4 阶段 3 -- 完成依赖注入

完成依赖注入

(1)Autowired.java注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Autowired 自动依赖注入
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Autowired {
}

(2)MonsterDao.java,MonsterService.java,加入 Autowired 注解

import com.spring.annotation.Component;

@Component(value = "monsterDao")
public class MonsterDao {
    public void hi() {
        System.out.println("hi 我是 monster Dao");
    }
}
import com.spring.annotation.Autowired;
import com.spring.annotation.Component;
import com.spring.annotation.Scope;

/**
 * MonsterService 是一个 Service
 * 1.如果指定value,注入容器时,以指定的value值为准
 * 2.如果没用指定value,则默认为类名首字母小写
 */
@Scope(value = "prototype")
@Component(value = "monsterService")//把MonsterService注入到我们自己的spring容器中
public class MonsterService {

    //表示该属性,是通过容器完成依赖注入
    //说明:这里只实现了按照属性名来进行组装
    @Autowired
    private MonsterDao monsterDao;
    public void m1() {
        //调用 monsterDao 的 hi()
        monsterDao.hi();
    }
}

(3)SpringApplicationContext.java 类中的 createBean 方法,实现依赖注入

private Object createBean(BeanDefinition bean){
    Class clazz = bean.getClazz();
    try {
        Object instance = clazz.newInstance();
        //完成依赖注入
        Field[] fields = clazz.getDeclaredFields();
        //遍历当前要创建的对象的所有字段
        for (Field field : fields) {
            //判断这个字段是否有@Autowired注解
            if (field.isAnnotationPresent(Autowired.class)){
                //如果该属性有@Autowired, 就进行组装
                //得到这个字段名字
                String fieldName = field.getName();
                //因为属性是private,需要爆破
                field.setAccessible(true);
                //进行组装,通过getBean方法获取到要组装的对象
                field.set(instance, getBean(fieldName));
            }
        }
        return instance;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

(4)编写主程序,查看依赖是否注入成功

public class AppMain {
    public static void main(String[] args) {
        SpringApplicationContext ioc = new SpringApplicationContext(SpringConfigXml.class);
        MonsterService monsterService = (MonsterService)ioc.getBean("monsterService");
        monsterService.m1();
        System.out.println("ok~");
    }
}

(5)运行效果

依赖注入成功!

5 阶段 4 -- bean后置处理器实现

实现自己的 bean 后置处理器

(1)InitializingBean.java 接口, 实现该接口的 Bean , 需要实现 Bean 初始化方法

/**
 * 1. 根据原生Spring 定义了一个InitializingBean
 * 2. 该InitializingBean接口有一个方法void afterPropertiesSet() throws Exception;
 * 3. afterPropertiesSet() 在Bean的 setter后执行,即就是初始化方法
 * 4. 当一个Bean实现这个接口后,就实现afterPropertiesSet() , 这个方法就是初始化方法
 */
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

(2)修改MonsterService.java、MonsterDao.java, 实现 InitializingBean 接口

import com.spring.annotation.Autowired;
import com.spring.annotation.Component;
import com.spring.annotation.Scope;
import com.spring.processor.InitializingBean;

/**
 * MonsterService 是一个 Service
 * 1.如果指定value,注入容器时,以指定的value值为准
 * 2.如果没用指定value,则默认为类名首字母小写
 */
@Scope(value = "prototype")
@Component(value = "monsterService")//把MonsterService注入到我们自己的spring容器中
public class MonsterService implements InitializingBean {

    //表示该属性,是通过容器完成依赖注入
    //说明:这里只实现了按照属性名来进行组装
    @Autowired
    private MonsterDao monsterDao;
    public void m1() {
        //调用 monsterDao 的 hi()
        monsterDao.hi();
    }

    /**
     * afterPropertiesSet就是在bean的setter方法执行完毕后被spring容器调用
     * 即就是初始化方法
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("MonsterService 初始化方法被调用 程序员在这里加入初始化的业务..");
    }
}
import com.spring.annotation.Component;
import com.spring.processor.InitializingBean;

@Component(value = "monsterDao")
public class MonsterDao implements InitializingBean {
    public void hi() {
        System.out.println("hi 我是 monster Dao");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("MonsterDao 初始化方法被调用...");
    }
}

(3)SpringApplicationContext.java 类中的createBean方法 , 在创建好 Bean 实例后,判断是否需要进行初始化

private Object createBean(BeanDefinition bean){
    Class clazz = bean.getClazz();
    try {
        Object instance = clazz.getDeclaredConstructor().newInstance();
        //完成依赖注入
        Field[] fields = clazz.getDeclaredFields();
        //遍历当前要创建的对象的所有字段
        for (Field field : fields) {
            //判断这个字段是否有@Autowired注解
            if (field.isAnnotationPresent(Autowired.class)){
                //如果该属性有@Autowired, 就进行组装
                //得到这个字段名字
                String fieldName = field.getName();
                //因为属性是private,需要爆破
                field.setAccessible(true);
                //进行组装,通过getBean方法获取到要组装的对象
                field.set(instance, getBean(fieldName));
            }
        }

        System.out.println("====创建好实例=====" + instance);
        //这里判断是否要执行Bean初始化方法
        //1. 判断当前创建的Bean对象是否实现了InitializingBean
        //2. instanceof 可以用来判断某个对象的运行类型是不是某个类型或者
        //  某个类型的子类型
        if (instance instanceof InitializingBean){
            // 转型成接口类型调用方法
            ((InitializingBean) instance).afterPropertiesSet();
            // 也可以使用反射调用
//                Method initMethod = clazz.getDeclaredMethod("afterPropertiesSet");
//                initMethod.invoke(instance);
        }
        return instance;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

(4)编写主程序,测试

public class AppMain {
    public static void main(String[] args) {
        SpringApplicationContext ioc = new SpringApplicationContext(SpringConfigXml.class);
        MonsterService monsterService = (MonsterService)ioc.getBean("monsterService");
        System.out.println("ok~");
    }
}

(5)运行效果

成功实现初始化方法!

(6)现在开始实现后置处理器,BeanPostProcessor.java 接口,创建MyBeanPostProcessor.java 类实现该接口,增加一个Car类,用于测试

/**
 * 1. 参考原生Spring容器定义一个接口BeanPostProcessor
 * 2. 该接口有两个方法postProcessBeforeInitialization 和 postProcessAfterInitialization
 * 3. 这两个方法,会对Spring容器的所有Bean生效
 */
public interface BeanPostProcessor {

    /**
     * postProcessBeforeInitialization在Bean的初始化方法前调用
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    /**
     * postProcessAfterInitialization在Bean的初始化方法后调用
     */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}
package com.spring.component;

import com.spring.annotation.Component;
import com.spring.processor.InitializingBean;

@Component
public class Car implements InitializingBean {
    String name = "小黄";
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Car的初始化方法..");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
import com.spring.annotation.Component;
import com.spring.processor.BeanPostProcessor;

/**
 * 1. 这是我们自己的一个后置处理器
 * 2. 实现了BeanPostProcessor
 * 3. 我们可以重写before和after方法
 * 4. 在Spring容器中,仍然把HspBeanPostProcessor当做一个Bean对象, 要注入到容器
 * 5. 需要加上@Component 标识
 * 6. 我们要让HspBeanPostProcessor成为真正的后置处理器, 需要在容器中加入业务代码
 * 7. 还要考虑多个后置处理器对象注入到容器问题
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {

        //后置处理器会对所有的bean生效,这里就可以对Car对象进行单独的处理
        if (bean instanceof Car){
            System.out.println("这是一个Car对象,我可以处理");
        }

        System.out.println("后置处理器HspBeanPostProcessor Before调用 bean类型="
                + bean.getClass() + " bean的名字=" + beanName);
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("后置处理器HspBeanPostProcessor After调用 bean类型="
                + bean.getClass() + " bean的名字=" + beanName);
        return bean;
    }
}

(7)修改 SpringApplicationContext.java 容器类

添加属性,存放后置处理器对象

//定义一个属性beanPostProcessorList, => 存放后置处理器
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

修改dealFile方法,在以下位置加入以下代码,将后置处理器对象放入集合中

//判断该类是否有 @Component
if (aClass.isAnnotationPresent(Component.class)) {

    //1. 为了方便,这里将后置处理器放入到一个ArrayList
    //2. 如果发现是一个后置处理器, 放入到 beanPostProcessorList
    //3. 在原生的Spring容器中, 对后置处理器还是走的getBean, createBean
    //   , 但是需要我们在singletonObjects 加入相应的业务逻辑,这里进行了简化

    //判断当前的这个class对象有没有实现BeanPostProcessor
    //说明, 这里我们不能使用 instanceof 来判断clazz是否实现了BeanPostProcessor
    //原因: clazz不是一个实例对象,而是一个类对象/clazz, 可以使用isAssignableFrom
    if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
        BeanPostProcessor beanPostProcessor =
                (BeanPostProcessor) aClass.newInstance();
        //放入到beanPostProcessorList
        beanPostProcessorList.add(beanPostProcessor);
        return;
    }
    。。。。。
}

修改create方法,增加一个参数beanName,并在初始化方法前后调用后置处理器方法

private Object createBean(BeanDefinition bean, String beanName)

create方法修改部分代码如下

System.out.println("====创建好实例=====" + instance);

//在Bean的初始化方法前,调用后置处理器的before方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
    //在后置处理器的before方法中,可以对容器的bean实例进行处理
    //然后返回处理后的实例
    Object current = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
    //这样处理,如果返回null,对bean对象不会造成影响,后置处理器中对bean做出的修改依然会生效
    if (current != null){
        instance = current;
    }
}


//这里判断是否要执行Bean初始化方法
//1. 判断当前创建的Bean对象是否实现了InitializingBean
//2. instanceof 可以用来判断某个对象的运行类型是不是某个类型或者
//  某个类型的子类型
if (instance instanceof InitializingBean){
    // 转型成接口类型调用方法
    ((InitializingBean) instance).afterPropertiesSet();
    // 也可以使用反射调用
    // Method initMethod = clazz.getDeclaredMethod("afterPropertiesSet");
    //  initMethod.invoke(instance);
}

//在Bean的初始化方法后,调用后置处理器的after方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
    //在后置处理器的after方法中,可以对容器的bean实例进行处理
    //然后返回处理后的实例
    Object current = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
    //这样处理,如果返回null,对bean对象不会造成影响
    if (current != null){
        instance = current;
    }
}

(8)编写主类测试

package com.spring;

import com.spring.component.MonsterService;
import com.spring.ioc.SpringApplicationContext;
import com.spring.ioc.SpringConfigXml;

public class AppMain {
    public static void main(String[] args) {
        SpringApplicationContext ioc = new SpringApplicationContext(SpringConfigXml.class);
        MonsterService monsterService = (MonsterService)ioc.getBean("monsterService");
        System.out.println("ok~");
    }
}

(9)运行结果

后置处理器成功作用在所有bean上

6 阶段 5 -- AOP机制实现

实现一个简单的AOP,这里做了简化,使用的硬编码,写死了

(1)创建注解Aspect.java,Before.java,AfterReturning.java

package com.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
    String value() default "";
}
package com.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Before {
    String value();
    String argNames() default "";
}
package com.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface AfterReturning {
    String value() default "";

    String pointcut() default "";

    String returning() default "";

    String argNames() default "";
}

(2)创建接口 SmartAnimalable.java,实现类 SmartDog.java,切面类 SmartAnimalAspect.java

package com.spring.component;

@SuppressWarnings("all")
public interface SmartAnimalable {
    //求和
    float getSum(float i, float j);
    //求差
    float getSub(float i, float j);
}
package com.spring.component;

import com.spring.annotation.Component;

@Component
public class SmartDog implements SmartAnimalable {
    @Override
    public float getSum(float i, float j) {
        float result = i + j;
        System.out.println("SmartDog-getSum方法内部打印result = " + result);
        return result;
    }

    @Override
    public float getSub(float i, float j) {
        float result = i - j;
        System.out.println("SmartDog-getSub方法内部打印result = " + result);
        return result;
    }
}
package com.spring.component;

import com.spring.annotation.AfterReturning;
import com.spring.annotation.Aspect;
import com.spring.annotation.Before;
import com.spring.annotation.Component;

/**
 * SmartAnimalAspect当做一个切面类来使用
 */
@Aspect
@Component
public class SmartAnimalAspect {

    @Before(value = "execution com.spring.aop.aspectj.SmartDog getSum")
    public static void showBeginLog() {

        System.out.println("前置通知..");
    }

    @AfterReturning(value = "execution com.spring.aop.aspectj.SmartDog getSum")
    public static void showSuccessLog() {

        System.out.println("返回通知..");
    }
}

(3)修改 MyBeanPostProcessor.java 类中的 postProcessAfterInitialization方法,实现AOP,返回代理对象

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    System.out.println("后置处理器HspBeanPostProcessor After调用 bean类型="
            + bean.getClass() + " bean的名字=" + beanName);

    //实现AOP,返回代理对象,即对Bean进行包装
    if ("smartDog".equals(beanName)){
        //使用jdk的动态代理,返回bean的代理对象
        Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                SmartAnimalAspect.showBeginLog();
                Object res = method.invoke(bean,args);
                SmartAnimalAspect.showSuccessLog();
                return res;
            }
        });
        return proxyInstance;
    }
    return bean;
}

(4)创建 AOPTest.java

package com.spring;

import com.spring.annotation.AfterReturning;
import com.spring.annotation.Before;
import com.spring.component.SmartAnimalAspect;

import java.lang.reflect.Method;

public class AOPTest {
    public static void main(String[] args) throws Exception {

        //1. 获取SmartAnimalAspect的class对象
        Class<SmartAnimalAspect> smartAnimalAspectClass = SmartAnimalAspect.class;
        //2. 遍历该类的所有方法
        for (Method declaredMethod : smartAnimalAspectClass.getDeclaredMethods()) {
            //如果切面类的方法有Before注解
            if (declaredMethod.isAnnotationPresent(Before.class)) {
                //得到切面类的切入方法名
                System.out.println("m:= " + declaredMethod.getName());
                //得到Before(value="xxxx")
                //得到Before注解
                Before annotation = declaredMethod.getAnnotation(Before.class);
                //得到Before注解的value
                System.out.println("value:= " + annotation.value());

                //调用切入方法[通过反射调用]
                declaredMethod.invoke(smartAnimalAspectClass.newInstance(), null);

            } else if (declaredMethod.isAnnotationPresent(AfterReturning.class)) {

                //如果发现切面类有AfterReturning注解,同样可以进行处理..
                System.out.println("m:= " + declaredMethod.getName());
                AfterReturning annotation = declaredMethod.getAnnotation(AfterReturning.class);
                System.out.println("value:= " + annotation.value());

                //调用切入方法[反射调用]
                declaredMethod.invoke(smartAnimalAspectClass.newInstance(), null);
            }
        }
    }
}

(5)运行结果

  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值