有关Spring的所有文章都收录于我的专栏:👉Spring👈
目录
前置准备
第一步、创建我们自定的注解
第二步、创建我们自己的容器类
测试
总结
相关文章
【Spring(一)】如何获取对象(Bean) | 【Spring(一)】如何获取对象(Bean) |
【Spring(二)】java对象属性的配置(Bean的配置) | 【Spring(二)】java对象属性的配置(Bean的配置) |
【Spring(三)】熟练掌握Spring的使用 | 【Spring(三)】熟练掌握Spring的使用 |
【Spring(四)】Spring基于注解的配置方式 | 【Spring(四)】Spring基于注解的配置方式 |
【Spring(五)】引入篇:AOP的底层原理之动态代理 | 【Spring(五)】引入篇:AOP的底层原理之动态代理 |
【Spring(六)】使用篇:AOP在开发中的使用 | 【Spring(六)】使用篇:AOP在开发中的使用 |
前置准备
在此之前我们先的了解原生Spring容器中有什么,以及它们的功能都是什么,我们才能有目的实现它。我们先在Spring容器中注入一个Bean。
第一步、创建我们自定的注解
@ComponentScan
这个注解用于标注配置类。我们手写的Spring容器使用的都是基于注解的方式。这个配置类就相当于我们的XML配置文件中配置扫描的包的路径。
package com.jl.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author long
* @date 2022/9/4
* @Target 指定我们的Component注解可以修饰Type程序元素
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value() default "";
}
@Component
此注解用于标注Bean对象。我们这里只写一个@Component`,其他例如:@Service这些都是相同的原理。
package com.jl.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 Component {
// 可以通过此注解指定bean的id值
String value() default "";
}
@Scope
此注解用于声明Bean为单例还是多例。
package com.jl.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 可以指定bean的作用范围
* singleton,prototype
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
String value() default "";
}
@Autowired
用于自动装配的注解。
package com.jl.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
// 可以通过此注解指定bean的id值
// String value() default "";
}
@Aspect
用于标注切面类的注解。
package com.jl.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 Aspect {
String value() default "";
}
@Before
前置通知的注解。
package com.jl.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Before {
String value();
String argNames() default "";
}
@AfterReturning
返回通知的注解。
package com.jl.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterReturning {
String value() default "";
String pointcut() default "";
String returning() default "";
String argNames() default "";
}
@After
后置通知的注解。
package com.jl.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface After {
String value();
String argNames() default "";
}
第二步、创建我们自己的容器类
在【一】中我们可以看到原生Spring容器中有几个很重要的属性:
beanDefinitionMap
:用于存放Bean的配置信息。singletonObjects
:存放创建好的Bean实例。beanPostProcessorList
:我们这里再添加到一个存放后置处理器的数组。
private Class configClass;
// 定义属性BeanDefinitionMap->存放BeanDefinition对象
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
// 定义属性SingletonObjects->存放单例对象
private ConcurrentHashMap<String,Object> singletonObjects= new ConcurrentHashMap<>();
// 定义属性,存放我们的后置处理器
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
扫描类
// 该方法完成对指定包的扫描,并将Bean信息封装到BeanDefinition对象,再放入Map中
public void beanDefinitionByScan(Class configClass){
this.configClass = configClass;
//1. 获取要扫描的包
ComponentScan componentScan =
(ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
//2. 通过ComponentScan的value =》即要扫描的包
String path = componentScan.value();
//得到要扫描包下的所有资源(.class)
//1) 得到类的加载器
ClassLoader classLoader = JlSpringApplicationContext.class.getClassLoader();
//2) 通过类的加载器获取到要扫描的包的资源url
path = path.replace(".","/");
URL resource = classLoader.getResource(path);
//3) 将要加载的资源(.class)路径下的文件进行遍历=》io
File file = new File(resource.getFile());
if (file.isDirectory()){
File[] files = file.listFiles();
for (File f : files) {
//class文件的绝对路径
String fileAbsolutePath = f.getAbsolutePath();
// 这里我们进行过滤,只处理.class文件
if (fileAbsolutePath.endsWith(".class")) {
//1. 获取到类名
String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//2. 获取类的全路径
String classFullName = path.replace("/", ".") + "." + className;
//3. 判断该.class文件是不是需要注入到容器中;看该类是不是有注解@Component @Service
try {
//这是我们就得到了该类的Class对象
// 这里也可以通过class.forName得到一个Class对象
// 区别是:class.forName()会调用类的静态方法,classLoader.loadClass()不会
Class<?> clazz = classLoader.loadClass(classFullName);
//aClass.isAnnotationPresent(Component.class) 判断该类是否有@Component注解
if (clazz.isAnnotationPresent(Component.class)){
System.out.println("这是一个SpringBean=" + clazz + " 类名=" + className);
// 为了方便,我们将后置处理器放入集合中(真实的还是在走createBean和getBean这些逻辑,这里是简化的)
// 如果是一个后置处理器就放入集合中
// 这里我们不能通过instanceof来判断是否实现了BeanPostProcessor
// 原因:这个的clazz是一个类对象,不是一个实例对象
if (BeanPostProcessor.class.isAssignableFrom(clazz)){
BeanPostProcessor beanPostProcessor = (BeanPostProcessor)clazz.newInstance();
beanPostProcessorList.add(beanPostProcessor);
continue;
}
//先得到beanName
// 1. 得到component注解
Component declaredAnnotation = clazz.getDeclaredAnnotation(Component.class);
// 2. 得到value值(1.配置了value 2.没有配置value)
String beanName = declaredAnnotation.value();
if ("".equals(beanName)){ // 如果没有写value
// 将该类的类名首字母小写作为beanName
beanName = StringUtils.uncapitalize(className);
}
// 3. 将bean的信息封装到BeanDefinition对象
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
// 4. 获取scope的值
if(clazz.isAnnotationPresent(Scope.class)){// 如果有scope值
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
}else { //如果没有scope值
beanDefinition.setScope("singleton");
}
// 5. 将BeanDefinition放入到Map中
beanDefinitionMap.put(beanName,beanDefinition);
}else {
System.out.println("这不是一个SpringBean=" + clazz + " 类名" + className);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
- 因为我们需要知道需要扫描的包的路径,所以需要借助
配置类
。我们这里将配置类的Class
对象作为参数传递给我们的容器类的构造器
(这一步在容器的构造器中体现)。 - 有了配置类的
Class对象
之后,我们就可以通过@ComponentScan
拿到要扫描类的路径。 - 拿到包的路径之后,就得去扫描包中的类,而且得判断哪些类是加了
@Component
。只有加了此注解的将来才可以注入到容器中。 - 如果有
@Component
,那么还得判断它是否是后置处理器,如何是后置处理器,实例化之后就将其直接加入到后置处理器集合中。 - 如果不是后置处理器,接下来拿到
@Component
中的value值。如果没有value值为空,就默认按照id=类名首字母小写
的方式命名。如果value值不为空,就将获取到的value值作为id。 - 接下来判断,类上是否有
@Scope
。如果有就拿到它的value值,反之就默认为singleton(单例)
。最后将此信息存入到BeanDefinition
中。BeanDefinition
结构:
package com.jl.spring.ioc;
/**
* 用于记录bean的信息(bean为单例还是多例Scope;bean对应的class对象,反射可以生成对应的对象)
*
*/
public class BeanDefinition {
private String scope;
private Class clazz;
public BeanDefinition(String scope, Class clazz) {
this.scope = scope;
this.clazz = clazz;
}
public BeanDefinition() {
}
@Override
public String toString() {
return "BeanDefinition{" +
"scope='" + scope + '\'' +
", clazz=" + clazz +
'}';
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
}
- 之后将我们得到的
beanName(也就是id值)
和beanDefinition(记录单例还是多例)
,存到我们的beanDefinitionMap
。
完成Bean实例的创建
在上一步中我们对所有的类进行了扫描,并且将所有Bean的信息存入到了beanDefinitionMap
中。接下来我们就可以创建Bean实例了。
// 完成 createBean(BeanDefinition beanDefinition)方法
private Object createBean(String beanName,BeanDefinition beanDefinition){
// 得到bean的class对象
Class clazz = beanDefinition.getClazz();
// 使用反射得到实例
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
// 注入对象
// 1. 遍历当前要创建的对象的所有字段
for (Field declaredField : clazz.getDeclaredFields()){
//2. 判断该字段是否有Autowired修饰
if (declaredField.isAnnotationPresent(Autowired.class)){
// 3.得到字段的名称
String name = declaredField.getName();
// 4.通过getBean方法来获取要组装对象
Object bean = getBean(name);
// 5. 进行组装
// 因为属性是私有的,所以要暴破
declaredField.setAccessible(true);
declaredField.set(instance,bean);
}
}
System.out.println("创建好了一个实例" + instance);
// 我们在Bean的初始化方法前,调用我们后置处理器的before方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
// 在后置处理器的before方法,可以对容器生成的bean进行处理
// 然后返回处理后的bean实例
Object current = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
if (current != null){
instance = current;
}
}
//判断是否需要执行Bean的初始化方法
// 1. 判断当前创建的Bean对象是否实现了InitializingBean
if (instance instanceof InitializingBean){ //如果实现了InitializingBean
// 将 instance转成接口类型
try {
((InitializingBean)instance).afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
}
// 我们在Bean的初始化方法前,调用我们后置处理器的after方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
// 在后置处理器的after方法,可以对容器生成的bean进行处理
// 然后返回处理后的bean实例
Object current = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
if (current != null){
instance = current;
}
}
System.out.println("-----------------------------------------");
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 如果反射对象失败,则返回空
return null;
}
- 我们从
BeanDefinition
中拿到需要创建的Class对象。 - 使用Class对象通过反射来创建Bean对象实例。
- 因为我们创建对象中还有属性,所以还得考虑自动装配的情况。
- 拿到所有Class对象所有的
Field
对象数组,遍历判断是否有@Autowired
。如果有就拿到此属性的名称,以此名称作为id去获取容器中的创建好的Bean实例。最后通过反射完成对属性的赋值。这里还得对属性进行暴破,因为属性是私有的. - 接下来还不能将Bean注入到容器中,因为我们还有
后置处理器
和初始化类
。 BeanPostProcessor
结构:
package com.jl.spring.processor;
import org.apache.commons.lang.StringUtils;
/**
* 参考原生Spring容器定义的一个接口
* 该接口有两个方法
*/
public interface BeanPostProcessor {
/**
* 这连个方法会对所有的bean生效
* 该方法在bean的初始化方法前调用
* @param bean
* @param beanName
* @return
*/
default Object postProcessBeforeInitialization(Object bean, String beanName){
return bean;
};
/**
* 该方法在bena的初始化方法之后调用
* @param bean
* @param beanName
* @return
*/
default Object postProcessAfterInitialization(Object bean, String beanName){
return bean;
};
}
- 遍历我们的
beanPostProcessorList(后置处理器集合)
,调用它们的postProcessBeforeInitialization()
,实现对Bean实例的前置处理。 - 判断当前的Bean对象是否实现了
InitializingBean
。如果实现了,执行它的afterPropertiesSet()
。InitializingBean
结构如下:
package com.jl.spring.processor;
/**
* 根据原生Spring定义一个接口
* 这个接口有一个方法
* afterPropertiesSet在Bean的Setter方法后执行,即就是我们的初始化方法
* 当一个Bean实现这个接口后,就实现afterPropertiesSet
*/
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
- 遍历我们的
beanPostProcessorList(后置处理器集合)
,调用它们的postProcessAfterInitialization()
,实现对Bean实例的后置处理。 - 最后返回我们的创建好的Bean实例。
获取Bean实例
// 编写方法返回容器的对象
public Object getBean(String name){
// 判断传入的beanName是否在beanDefinition中存在
if (beanDefinitionMap.containsKey(name)){
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
// 得到beanDefinition的scope,分别进行处理
if("singleton".equalsIgnoreCase(beanDefinition.getScope())){
// 单例的,直接从单例池中获取
return singletonObjects.get(name);
}else { // 如果不是单例,就通过createBean,反射一个对象
return createBean(name,beanDefinition);
}
}else {
// 如果不存在
throw new NullPointerException("没有该bean");
}
}
- 获取Bean实例,首先就得判断容器中是否有该Bean的信息。
- 判断要获取的Bean是否是单例,如果是单例就直接从单例池
singletonObjects
中获取。如果不是就调用createBean()
,造一个Bean实例返回。
容器的构造方法
public JlSpringApplicationContext(Class configClass){
beanDefinitionByScan(configClass);
// 通过beanDefinition对象,初始化singletonObject单例池
Enumeration<String> keys = beanDefinitionMap.keys();
// 遍历所有的beanDefinition对象
while (keys.hasMoreElements()){
String beanName = keys.nextElement();
// 通过beanName得到对应的beanDefinition对象
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
// 判断该bean是singleton还是一个prototype
if ("singleton".equalsIgnoreCase(beanDefinition.getScope())){
// 将该bean实例放入到singletonObjects这个集合中
Object bean = createBean(beanName,beanDefinition);
singletonObjects.put(beanName,bean);
}
}
// System.out.println("单例池" + singletonObjects);
}
测试
Bean的测试(默认)
配置类
package com.jl.spring.ioc;
import com.jl.spring.annotation.ComponentScan;
/**
* 这是一个配置类,作用类似我们原生spring的beans.xml 容器配置文件
*/
@ComponentScan(value = "com.jl.spring.component")
public class JlSpringConfig {
}
测试类:
package com.jl.spring;
import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;
public class AppMain {
public static void main(String[] args) {
JlSpringApplicationContext jlSpringApplicationContext =
new JlSpringApplicationContext(JlSpringConfig.class);
Object car = jlSpringApplicationContext.getBean("car");
System.out.println(car);
}
}
结果截图:
Bean的测试(通过指定id)
package com.jl.spring.component;
import com.jl.spring.annotation.Component;
@Component(value = "myCar")
public class Car {
}
测试类:
package com.jl.spring;
import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;
public class AppMain {
public static void main(String[] args) {
JlSpringApplicationContext jlSpringApplicationContext =
new JlSpringApplicationContext(JlSpringConfig.class);
Object car = jlSpringApplicationContext.getBean("myCar");
System.out.println(car);
}
}
结果截图:
自动装配测试
package com.jl.spring.component;
import com.jl.spring.annotation.Component;
import com.jl.spring.processor.InitializingBean;
@Component(value = "monsterDao")
public class MonsterDao implements InitializingBean {
public void hi(){
System.out.println("MonsterDao-hi()被调用。。。");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("MonsterDao初始化方法被调用");
}
}
package com.jl.spring.component;
import com.jl.spring.annotation.Autowired;
import com.jl.spring.annotation.Component;
import com.jl.spring.annotation.Scope;
import com.jl.spring.processor.InitializingBean;
/**
* MonsterService是一个service
*/
@Component(value = "monsterService") // 把MonsterService注入到我们自己的Spring容器中
public class MonsterService implements InitializingBean {
@Autowired
private MonsterDao monsterDao;
public void m1(){
monsterDao.hi();
}
/**
* 该方法就是Bean的方法执行过后,被容器调用
* 即就是初始化方法
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("MonsterService初始化方法被调用");
}
}
测试类:
package com.jl.spring;
import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;
public class AppMain {
public static void main(String[] args) {
JlSpringApplicationContext jlSpringApplicationContext =
new JlSpringApplicationContext(JlSpringConfig.class);
Object bean = jlSpringApplicationContext.getBean("monsterService");
System.out.println(bean);
}
}
结果截图:
单例多例测试
package com.jl.spring.component;
import com.jl.spring.annotation.Autowired;
import com.jl.spring.annotation.Component;
import com.jl.spring.annotation.Scope;
import com.jl.spring.processor.InitializingBean;
/**
* MonsterService是一个service
*/
@Component(value = "monsterService") // 把MonsterService注入到我们自己的Spring容器中
@Scope(value = "prototype")
public class MonsterService implements InitializingBean {
@Autowired
private MonsterDao monsterDao;
public void m1(){
monsterDao.hi();
}
/**
* 该方法就是Bean的方法执行过后,被容器调用
* 即就是初始化方法
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("MonsterService初始化方法被调用");
}
}
测试类
package com.jl.spring;
import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;
public class AppMain {
public static void main(String[] args) {
JlSpringApplicationContext jlSpringApplicationContext =
new JlSpringApplicationContext(JlSpringConfig.class);
Object bean = jlSpringApplicationContext.getBean("monsterService");
Object bean1 = jlSpringApplicationContext.getBean("monsterService");
System.out.println(bean);
System.out.println(bean1);
}
}
结果截图:
后置处理器和初始化方法的测试
package com.jl.spring.component;
import com.jl.spring.annotation.Component;
import com.jl.spring.processor.InitializingBean;
@Component(value = "myCar")
public class Car implements InitializingBean {
public Car() {
System.out.println("Car无参构造被调用...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化方法");
}
}
package com.jl.spring.component;
import com.jl.spring.annotation.Component;
import com.jl.spring.processor.BeanPostProcessor;
@Component
public class BeanPostProcessorImpl implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("前置通知");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("后置通知");
return null;
}
}
测试类:
package com.jl.spring;
import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;
public class AppMain {
public static void main(String[] args) {
JlSpringApplicationContext jlSpringApplicationContext =
new JlSpringApplicationContext(JlSpringConfig.class);
Object car = jlSpringApplicationContext.getBean("myCar");
System.out.println(car);
}
}
结果截图:
AOP的编写
我们AOP和后置处理器有所联系。AOP就是利用前后置处理器进行切面处理。单例加强。
我们先看一下,用后置处理器实现的切面。
package com.jl.spring.component;
public interface SmartAnimalable {
float getSum(float i ,float j);
float getSub(float i ,float j);
}
package com.jl.spring.component;
import com.jl.spring.annotation.Component;
@Component(value="smartDog")
public class SmartDog implements SmartAnimalable{
@Override
public float getSum(float i, float j) {
float res = i+j;
System.out.println("SmartDog-getSum-res=" + res);
return res;
}
@Override
public float getSub(float i, float j) {
float res = i -j;
System.out.println("SmartDog-getSub-res=" + res);
return res;
}
}
后置处理器实现类:
package com.jl.spring.component;
import com.jl.spring.annotation.Component;
import com.jl.spring.processor.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 这是我们自己的后置处理器
* 它是实现了BeanPostProcessor
* 我们可以重写里边的方法
* 在Spring容器中仍然将我们的后置处理器当作一个Bean来处理,要注入到容器中
* 还得考虑多个后置处理器的情况
*/
@Component
public class JlBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("后置处理器的JlBeanPostProcessor的before()方法被调用" + bean.getClass() + " beanName=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("后置处理器的JlBeanPostProcessor的after()方法被调用" + bean.getClass() + " beanName=" + beanName);
// 实现AOP,返回代理对象,即对Bean进行包装
if("smartDog".equals(beanName)){
// 使用JDK的动态代理,返回Bean的代理对象
Object proxyInstance = Proxy.newProxyInstance(JlBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method"+ method.getName());
Object result = null;
// 加入要进行前置通知处理的方法是getSum
if ("getSum".equals(method.getName())){
SmartAnimalAspect.showBeginLog();
result = method.invoke(bean,args);
// 进行返回通知的处理
SmartAnimalAspect.showSuccessLog();
}else {
result = method.invoke(bean,args);
}
return result;
}
});
// 如果bean是需要返回代理对象的,这里就直接返回代理对象
return proxyInstance;
}
// 如果不需要AOP处理,我们就返回原生对象
return bean;
}
}
看到这里不知道小伙伴们有种似曾相识的感juo。没错!这里就是我们【AOP引入篇】中提到的动态代理
。我们因为是简单演示,所以这里只是在postProcessAfterInitialization()
中做了处理。
测试类:
package com.jl.spring;
import com.jl.spring.component.MonsterService;
import com.jl.spring.component.SmartAnimalable;
import com.jl.spring.ioc.JlSpringApplicationContext;
import com.jl.spring.ioc.JlSpringConfig;
public class AppMain {
public static void main(String[] args) {
JlSpringApplicationContext jlSpringApplicationContext =
new JlSpringApplicationContext(JlSpringConfig.class);
// 测试AOP是否生效
SmartAnimalable smartDog = (SmartAnimalable)jlSpringApplicationContext.getBean("smartDog");
smartDog.getSum(10,2);
smartDog.getSub(10,2);
System.out.println(smartDog.getClass());
}
}
结果截图:
我们只对getSum
做了增强,所以结果显示也只是对getSum
的增强。
其实真正的AOP也和这个很类似,但他对很多内容进行了封装。我们下边模拟一个AOP:
package com.jl.spring.component;
public interface SmartAnimalable {
float getSum(float i ,float j);
float getSub(float i ,float j);
}
切面类
package com.jl.spring.component;
import com.jl.spring.annotation.*;
/**
* 先将SmartAnimalAspect当作一个切面类来使用
* 后面再改的更加灵活
*/
@Aspect
@Component
public class SmartAnimalAspect {
@Before(value = "execution float com.jl.spring.component.SmartDog.getSum")
public static void showBeginLog(){
System.out.println("前置通知");
}
@AfterReturning(value = "execution float com.jl.spring.component.SmartDog.getSum")
public static void showSuccessLog(){
System.out.println("返回通知");
}
}
package com.jl.spring.component;
import com.jl.spring.annotation.Component;
@Component(value="smartDog")
public class SmartDog implements SmartAnimalable{
@Override
public float getSum(float i, float j) {
float res = i+j;
System.out.println("SmartDog-getSum-res=" + res);
return res;
}
@Override
public float getSub(float i, float j) {
float res = i -j;
System.out.println("SmartDog-getSub-res=" + res);
return res;
}
}
测试类:
虽然是测试类,但这里边还对注解进行了处理,有兴趣的小伙伴可以将其抽取出来,做一些完善。
package com.jl.spring;
import com.jl.spring.annotation.AfterReturning;
import com.jl.spring.annotation.Before;
import com.jl.spring.component.SmartAnimalAspect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class JlTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<SmartAnimalAspect> smartAnimalAspectClass = SmartAnimalAspect.class;
for (Method declaredMethod : smartAnimalAspectClass.getDeclaredMethods()) {
if(declaredMethod.isAnnotationPresent(Before.class)){
String name = declaredMethod.getName();
Before annotation = declaredMethod.getAnnotation(Before.class);
String value = annotation.value();
Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
declaredMethod1.invoke(smartAnimalAspectClass.newInstance(),null);
}else if(declaredMethod.isAnnotationPresent(AfterReturning.class)){
String name = declaredMethod.getName();
Before annotation = declaredMethod.getAnnotation(Before.class);
String value = annotation.value();
Method declaredMethod1 = smartAnimalAspectClass.getDeclaredMethod(declaredMethod.getName());
declaredMethod1.invoke(smartAnimalAspectClass.newInstance(),null);
}
}
}
}
结果截图:
总结
以上就是我们手写的一个简易的Spring,主要是帮助大家理解Spring的基本执行流程。
如果文章中有描述不准确或者错误的地方,还望指正。您可以留言📫或者私信我。🙏
最后希望大家多多 关注+点赞+收藏^_^,你们的鼓励是我不断前进的动力!!!
感谢感谢~~~🙏🙏🙏