1 Spring 整体架构示意图
2 阶段 1 -- 编写自己的 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);
}
}
3 阶段 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)运行结果