Spring
Spring
什么是框架? 比如一个简历模板,你拿过来只需要把里面的内容改了就行,可以直接用
Spring的理念:使现有的技术更加容易使用,本身就是一个大杂烩,整合了现有的技术框架
Spring是什么:
-
spring是一个开源的免费的框架(容器)
-
spring是一个轻量级的、非入侵式的框架(就是他的引入不会导致原有的项目不能运行)
-
控制反转(IOC),面向切面编程(AOP)
-
支持事务的处理,对框架整合的支持(支持很多)
-
所有的类都需要装配到bean里面,然后所有的bean呢,就需要通过容器来取
- UserDao 数据库接口
- UserDaoImpl 数据库实现类
- UserService 业务接口
- UserServiceImpl 业务实现类
在我们之前的业务中,只要用户需求发生改变,我们就要根据用户的需求去修改原代码
但是在我们使用了一个Set接口实现之后,就发生了革命性的改变
private UserDao userDao;
public void getUser() {
userDao.getUser();
}
//利用set进行动态实现值的注入 俗称依赖注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,对象的实例化创建交由给程序控制,控制权在程序员自己手里
- 但是使用了set注入之后,程序就不再具有主动权,而是成为被动的接收对象,就将对象的创建和实例化过程交由用户自己来创建
这种思想,从本质上解决了问题,我们程序员就不用再去管理对象的创建了,大大降低了系统的耦合性,可以使我们更加专注与业务的实现和开发!这就是IOC的原型
框架之所以叫框架,是因为他帮我们做了很多东西,我们只需要进行使用就可以了
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的.
反转∶程序本身不创建对象,而变成被动的接收对象.依赖注入:就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收.
可以通过new ClassPathXmlApplicationContext去浏览一下底层源码.
我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的loC,一句话搞定:对象由Spring 来创建,管理,装配!
IOC创建对象的方式
- 使用无参构造对象,默认的
- 有参构造:用constructor-arg 标签 value赋值
- 下标赋值 index
- 通过类型创建 type
- 通过参数名设置 name
在程序执行的是,整个配置文件中的bean都会被创建,单例模式
Maven依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
Spring配置
- 别名标签 alias 下面的name更高级
- bean标签中 有一个id是唯一标识符 class是类 name是别名 例如name="user1,user2"可以取多个别名(关键)
- import标签 属性resource 可以导入其他的Spring配置文件,可以将多个配置文件合并成一个,便于管理合作开发
核心配置 applicationContext.xml
applicationContext.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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- 指定包下的注解就会生效 *通配符,代表所有包 ->
<context:component-scan base-package="*.*"></context:component-scan>
<!--bean就是java对象 , 由Spring创建和管理-->
</beans>
<!-- 配置注解的支持 -->
<context:annotaion-config/>
<!-- 指定包下的注解就会生效 *通配符,代表所有包,有了这个就不需要上面那个了-->
<context:component-scan base-package="*.*"></context:component-scan>
如何使用?
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
//这样就不需要强转了
Student student = context.getBean("student",Student.class);
System.out.println(student.getName());
DI依赖注入
依赖:bean对象的创建依赖于容器 ; 注入:bean对象中的所有属性,都由容器来注入!
- 构造器注入
- set方式注入
- 拓展方式注入
不同类型的注入方式:
引入命名空间:c和p
需要先导入约束
p命名空间,可以直接在bean标签上注入属性的值 p:属性名="value" 属性注入property
xmlns:p="http://www.springframework.org/schema/p"
c命名空间 通过 c:属性名-ref=“value”来赋值 构造器注入 construct
xmlns:c="http://www.springframework.org/schema/c"
bean的作用域scope
-
singleton单例模式 始终是一个对象 (单线程推荐使用)
手写一个单例模式?饿汉模式public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() {}; public static Singleton getInstance() { return singleton; } }
-
prototype原型模式 每次从容器中get的时候,都会产生一个新的bean (多线程推荐使用)
- 其余的作用域:request、session、application 只能在web开发中使用到
Spring 的三种装配方式
- xml中的显式配置装配
- java代码实现的显式配置装配
- 隐式 实现装配
- byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id !
bean的id要唯一 - byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean !
bean的类型要唯一
- byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id !
注解
自动装配
- @Autowired bytype对象必须存在(常用) @Resource byname找不到就用bytype
- @Nullable 该字段可以为空
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value="xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入
需要引入命名空间和支持
xmlns:context="http://www.springframework.org/schema/context"
<!-- 配置注解的支持 -->
<context:component-scan base-package="*.*"></context:component-scan>
- @Component 组件,写在类上,等价于spring创建了一个bean
- dao @Repository
- service @Service
- controller @Controller
- 他们四个的功能是一样的,就是便于我们分辨而已
- @Value 写在实体类下属性上,进行赋值,类似于在bean中给属性赋值
- @Scope("") 作用域,原型和单例
小结:
- xml和注解:
- xml更加万能,适用于任何场合!维护简单方便。注解不是自己类使用不了,维护相对复杂!xml与注解最佳实践:
- xml 用来管理bean;
- 注解只负责完成属性的注入;
代理
什么是代理?
什么是面向切面编程?
代理的作用是什么,为什么要代理?
静态代理:
代理,例如有这样一个关系,
租客,中介,房东
房东呢就想提供一个房源,不想管其他事情,而此时就有一个中介这么一个对象,他能帮你签合同,带租客看房等等。而租客想租房找不到房东的时候,就有中介这么个东西,他能代替房东发挥它的作用。而此时我们面对的对象就变成了中介,中介呢也就是做到了其中的一个代理的作用。
动态代理:
-
动态代理和静态代理的剧角色是一样的
-
动态代理的代理类是动态生成的,不是我们直接写好的
-
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口---jdk 动态代理 我们在这里使用
- 基于类:cglib
- java字节码实现
-
动态代理代理的是接口
需要了解两个类:Proxy 代理,InvocationHandler 调用处理程序 invoke(调用,引用,执行)
每一个代理实例,他都有关联一个调用处理程序
我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// proxy : 代理类
// method : 代理类的调用处理程序的方法对象.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName){
System.out.println("执行了"+methodName+"方法");
}
}
测试
public class Test {
public static void main(String[] args) {
//真实对象
UserServiceImpl userService = new UserServiceImpl();
//代理对象的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService); //设置要代理的对象
UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
proxy.delete();
}
}
Method是什么,就是我们要执行的目标对象的方法,
AOP
动态代理代理的是接口,
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
-
三种方式
- 通过 Spring API 实现
<!--注册bean--> <bean id="userService" class="com.mao.service.UserServiceImpl"/> <bean id="log" class="com.mao.log.Log"/> <bean id="afterLog" class="com.mao.log.AfterLog"/> <!--aop的配置--> <aop:config> <!--切入点 expression:表达式匹配要执行的方法--> <aop:pointcut id="pointcut" expression="execution(* com.mao.service.UserServiceImpl.*(..))"/> <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config>
- 自定义类来实现Aop
<!--第二种方式自定义实现--> <!--注册bean--> <bean id="diy" class="com.mao.config.DiyPointcut"/> <!--aop的配置--> <aop:config> <!--第二种方式:使用AOP的标签实现--> <aop:aspect ref="diy"> <aop:pointcut id="diyPonitcut" expression="execution(* com.mao.service.UserServiceImpl.*(..))"/> <aop:before pointcut-ref="diyPonitcut" method="before"/> <aop:after pointcut-ref="diyPonitcut" method="after"/> </aop:aspect> </aop:config>
- 使用注解实现
第一步:编写一个注解实现的增强类
package com.kuang.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.mao.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.mao.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.mao.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
第二步:在Spring配置文件中,注册bean,并增加支持注解的配置
<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
本文来自博客园,作者:没有烦恼的猫猫,转载请注明原文链接:https://www.cnblogs.com/maomao777/p/16000210.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~