spring底层机制环境搭建
1.模块创建和依赖引入
聚合模块,下面有一个myspring

查看父模块是否管理了子模块

myspring模块引入基本包
<dependencies>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
<version>5.3.8</version>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-aspects</artifactid>
<version>5.3.8</version>
</dependency>
</dependencies>2.进行环境搭建
目录概览

usercontroller.java
package com.sunxiansheng.myspring.component;
import org.springframework.stereotype.component;
/**
* description: 就是一个controller组件
* @author sun
* @create 2024/8/4 13:53
* @version 1.0
*/
@component
public class usercontroller {
}userservice.java
package com.sunxiansheng.myspring.component;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
/**
* description: 一个service组件
* @author sun
* @create 2024/8/4 13:54
* @version 1.0
*/
@component
public class userservice {
/**
* 依赖注入userdao
*/
@autowired
private userdao userdao;
public void add() {
system.out.println("userservice 调用了userdao的add方法");
userdao.add();
}
}userdao.java
package com.sunxiansheng.myspring.component;
import org.springframework.stereotype.component;
/**
* description: 一个dao组件
* @author sun
* @create 2024/8/4 13:53
* @version 1.0
*/
@component
public class userdao {
public void add() {
system.out.println("userdao add...");
}
}appmain.java
package com.sunxiansheng.myspring;
import com.sunxiansheng.myspring.component.usercontroller;
import com.sunxiansheng.myspring.component.userdao;
import com.sunxiansheng.myspring.component.userservice;
import org.springframework.context.applicationcontext;
import org.springframework.context.support.classpathxmlapplicationcontext;
/**
* description: 启动类
* @author sun
* @create 2024/8/4 13:59
* @version 1.0
*/
public class appmain {
public static void main(string[] args) {
// 从类路径下加载beans.xml配置文件
applicationcontext ioc = new classpathxmlapplicationcontext("beans.xml");
// 从容器中获取usercontroller对象,这里获取两次,看是否是同一个对象
usercontroller usercontroller1 = (usercontroller) ioc.getbean("usercontroller");
usercontroller usercontroller2 = (usercontroller) ioc.getbean("usercontroller");
system.out.println("usercontroller1 == usercontroller2 ? " + (usercontroller1 == usercontroller2));
// 从容器中获取userservice对象
userservice userservice = (userservice) ioc.getbean("userservice");
system.out.println("userservice = " + userservice);
// 从容器中获取userdao对象
userdao userdao = (userdao) ioc.getbean("userdao");
system.out.println("userdao = " + userdao);
}
}beans.xml
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.sunxiansheng.myspring.component"/>
</beans>测试

配置usercontroller.java为多例的,然后测试


userservice调用add方法,然后测试


引入bean后置处理器
1.位置

2.mybeanpostprocessor.java
package com.sunxiansheng.myspring.process;
import org.springframework.beans.factory.config.beanpostprocessor;
import org.springframework.stereotype.component;
/**
* description: bean的后置处理器
* @author sun
* @create 2024/8/4 14:19
* @version 1.0
*/
@component // 将这个类加入到容器中
public class mybeanpostprocessor implements beanpostprocessor {
/**
* 在每个bean的初始化方法之前执行
* @param bean
* @param beanname
* @return
*/
@override
public object postprocessbeforeinitialization(object bean, string beanname) {
// 这里可以提前对bean进行一些处理
system.out.println("postprocessbeforeinitialization..."+beanname+"=>"+bean.getclass());
return bean;
}
/**
* 在每个bean的初始化方法之后执行
* @param bean
* @param beanname
* @return
*/
@override
public object postprocessafterinitialization(object bean, string beanname) {
system.out.println("postprocessafterinitialization..."+beanname+"=>"+bean.getclass());
return bean;
}
}3.userservice.java 设置初始化方法

4.beans.xml配置扫描

5.测试

6.注意事项
- bean的后置处理器在初始化方法调用前后执行
- 触发时机为单例的第一次getbean和多例的每次getbean,也就是,每个bean都会经过bean的后置处理器处理
引入aop
1.目录

2.smartanimal.java
package com.sunxiansheng.myspring.aop;
/**
* description: smartanimal
* @author sun
* @create 2024/8/4 14:51
* @version 1.0
*/
public interface smartanimal {
public float getsum(float a, float b);
public float getsub(float a, float b);
}3.smartdog.java
package com.sunxiansheng.myspring.aop;
import org.springframework.stereotype.component;
/**
* description: smartdog
* @author sun
* @create 2024/8/4 14:51
* @version 1.0
*/
@component // 交给spring容器管理
public class smartdog implements smartanimal {
@override
public float getsum(float a, float b) {
system.out.println("smartdog...getsum...res=" + (a + b));
return a + b;
}
@override
public float getsub(float a, float b) {
system.out.println("smartdog...getsub...res=" + (a - b));
return a - b;
}
}4.smartanimalaspect.java
package com.sunxiansheng.myspring.aop;
import org.aspectj.lang.joinpoint;
import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.methodsignature;
import org.springframework.stereotype.component;
import java.util.arrays;
/**
* description: 切面类
* @author sun
* @create 2024/8/4 14:53
* @version 1.0
*/
@component // 交给spring容器管理
@aspect // 标注这是一个切面类
public class smartanimalaspect {
/**
* @param joinpoint 保存了要切入的方法的信息
* @before 前置通知
* execution(。。。) 切入表达式,表明要切入的方法,格式:格式:访问修饰符+返回类型 全类名 方法名(参数类型)
*/
@before(value = "execution(public float com.sunxiansheng.myspring.aop.smartdog.getsub(float, float))")
public void before(joinpoint joinpoint) {
// 获取方法签名
signature signature = joinpoint.getsignature();
system.out.println("方法执行开始-日志-方法名-" + signature.getname()
+ "-参数" + arrays.aslist(joinpoint.getargs()));
// 还可以获取目标对象,这样就可以反射进行任何操作了
smartdog target = (smartdog) joinpoint.gettarget();
system.out.println("目标对象-" + target.getclass());
}
/**
* @param joinpoint 保存了要切入的方法的信息
* @afterreturning 返回通知
*/
@afterreturning(value = "execution(public float com.sunxiansheng.myspring.aop.smartdog.getsub(float, float))")
public void afterreturning(joinpoint joinpoint) {
signature signature = joinpoint.getsignature();
system.out.println("方法执行正常结束-日志-方法名-" + signature.getname());
}
/**
* @param joinpoint
* @afterthrowing 异常通知
*/
@afterthrowing(value = "execution(public float com.sunxiansheng.myspring.aop.smartdog.getsub(float, float))")
public void throwing(joinpoint joinpoint) {
signature signature = joinpoint.getsignature();
system.out.println("方法出现异常-日志-方法名-" + signature.getname());
}
/**
* @param joinpoint
* @after 后置通知
*/
@after(value = "execution(public float com.sunxiansheng.myspring.aop.smartdog.getsub(float, float))")
public void after(joinpoint joinpoint) {
signature signature = joinpoint.getsignature();
system.out.println("方法最终执行完毕-日志-方法名-" + signature.getname());
}
/**
* 环绕通知
* @param joinpoint
* @return
* @throws throwable
*/
@around("execution(public float com.sunxiansheng.myspring.aop.smartdog.getsub(float, float))")
public object logmethodexecution(proceedingjoinpoint joinpoint) throws throwable {
methodsignature signature = (methodsignature) joinpoint.getsignature();
// 获取方法信息
string methodname = signature.getmethod().getname();
string classname = signature.getdeclaringtype().getsimplename();
system.out.println("环绕通知 method " + classname + "." + methodname);
// 获取目标对象
object targetobject = joinpoint.gettarget();
// 环绕通知获取目标对象
system.out.println("环绕通知获取目标对象:" + targetobject);
try {
// 前置通知:环绕通知获取参数
system.out.println("环绕通知获取参数:" + arrays.aslist(joinpoint.getargs()));
object result = joinpoint.proceed(); // 执行目标方法
// 返回通知:环绕通知获取结果
system.out.println("环绕通知获取结果:" + result);
return result;
} catch (exception e) {
// 异常通知
throw e;
} finally {
// 最终通知
system.out.println("环绕通知 method " + classname + "." + methodname);
}
}
}5.beans.xml开启aop注解并扫描aop包

6.appmain.java 测试aop


6.简单分析aop和后置处理器的关系

3.抛出问题
- 1.bean是怎么注入容器的?
- 2.为什么加了@autowired就能被依赖注入?
- 3.单例多例是怎么实现的?
- 4.bean的后置处理器是怎么实现的?
- 5.原生spring的aop是如何实现的?
4.将代码放到远程仓库
- vcs -》 share

- 查看仓库

总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论