Spring学习笔——呕心沥血上万字

DataAccess 用于数据访问,WEB 用于页面显示,核心容器也就是IOC部分。

控制反转(IOC)

控制反转(Inversion of Control)是指将对象的创建权反转(交给)Spring。

使用IOC就需要导入IOC相关的包,也就是上图中核心容器中的几个包:beans,context,core,expression四个包。

实现原理

传统方式创建对象:

UserDAO userDAO=new UserDAO();

进一步面向接口编程,可以多态:

UserDAO userDAO=new UserDAOImpl();

这种方式的缺点是接口和实现类高耦合,切换底层实现类时,需要修改源代码。程序设计应该满足OCP元祖,在尽量不修改程序源代码的基础上对程序进行扩展。此时,可以使用工厂模式:

class BeanFactory{

public static UserDAO getUserDAO(){

return new UserDAOImpl();

}

}

此种方式虽然在接口和实现类之间没有耦合,但是接口和工厂之间存在耦合。

使用工厂+反射+配置文件的方式,实现解耦,这也是 Spring 框架 IOC 的底层实现。

//xml配置文件

//

class BeanFactory{

public static Object getBean(String id){

//解析XML

//反射

Class clazz=Class.forName();

return clazz.newInstance();

}

}

IOC XML 开发

在 docs 文件中包含了 xsd-configuration.hmtl 文件。其中定义了 beans schema。

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

//在此配置bean

调用类:

ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“applicationContext.xml”);

UserService userService=(UserService)applicationContext.getBean(“userService”);

userService.save();

IOC 和 DI

DI 指依赖注入,其前提是必须有 IOC 的环境,Spring 管理这个类的时候将类的依赖的属性注入进来。

例如,在UserServiceImpl.java中:

public class UserServiceImpl implements UserService{

private String name;

public void setName(String name){

this.name=name;

}

public void save(){

System.out.println("save "+name);

}

}

在配置文件中:

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

测试代码:

@Test

public void demo2(){

//创建Spring工厂

ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“applicationContext.xml”);

UserService userService=(UserService)applicationContext.getBean(“userService”);

userService.save();

}

运行结果:

save tony

可以看到,在配置文件中配置的属性,在 Spring 管理该类的时候将其依赖的属性成功进行了设置。如果不使用依赖注入,则无法使用接口,只能使用实现类来进行设置,因为接口中没有该属性。

Spring 的工厂类

BeanFactory: 老版本的工厂类,在调用getBean()方法时,才会生成类的实例。

ApplicationContext: 在加载配置文件的时候,就会将 Spring 管理的类都实例化。有两个实现类:

ClassPathXmlApplicationContext: 加载类路径下的配置文件

FileSystemXmlApplicationContext: 加载磁盘下的配置文件

bean标签配置

id: 唯一约束,不能出现特殊字符

name: 理论上可以重复,但是开发中最好不要。可以出现特殊字符

生命周期:

init-method: bean被初始化的时候执行的方法

destroy-method: bean被销毁的时候执行的方法

作用范围:

scope: bean的作用范围,有如下几种,常用的是前两种

singleton: 默认使用单例模式创建

prototype: 多例

request: 在web项目中,spring 创建类后,将其存入到 request 范围中

session: 在web项目中,spring 创建类后,将其存入到 session 范围中

globalsession: 在web项目中,必须用在 porlet 环境

属性注入设置

构造方法方式的属性注入: Car 类在构造方法中有两个属性,分别为 name 和 price。

set 方法属性注入: Employee 类在有两个 set 方法,分别设置普通类型的 name 和引用类型的 Car (使用 ref 指向引用类型的 id 或 name)。

P名称空间的属性注入: 首先需要引入p名称空间:

<beans xmlns=“http://www.springframework.org/schema/beans”

//引入p名称空间

xmlns:p=“http://www.springframework.org/schema/p”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

如果是普通属性:

如果是引用类型:

<bean id=“employee” class=“demo.Employee” p:name=“xiaoming” p:car-ref:“car”>

SpEL(Spring Expression Language)属性注入(Spring 3.x以上版本)

集合类型属性注入:

qirui

baoma

benchi

多模块开发配置

在加载配置文件的时候,加载多个配置文件

在一个配置文件中引入多个配置文件,通过实现

IOC 注解开发

示例

引入jar包: 除了要引入上述的四个包之外,还需要引入aop包。

创建 applicationContext.xml ,使用注解开发引入 context 约束(xsd-configuration.html)

<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 http://www.springframework.org/schema/context/spring-context.xsd">

组件扫描: 使用IOC注解开发,需要配置组件扫描,也就是哪些包下的类使用IOC的注解。

<context:component-scan base-package=“demo1”>

在类上添加注解

使用注解设置属性的值

属性如果有set方法,将属性注入的注解添加到set方法

属性没有set方法,将注解添加到属性上。

@Component(“UserDao”)//相当于配置了一个 其id为UserDao,对应的类为该类

public class UserDAOImpl implements UserDAO {

@Override

public void save() {

// TODO Auto-generated method stub

System.out.println(“save”);

}

}

注解详解

@Component

组件注解,用于修饰一个类,将这个类交给 Spring 管理。

有三个衍生的注解,功能类似,也用来修饰类。

@Controller:修饰 web 层类

@Service:修饰 service 层类

@Repository:修饰 dao 层类

2.属性注入

普通属性使用 @Value 来设置属性的值

对象属性使用 @Autowired ,这个注解是按照类型来进行属性注入的。如果希望按照 bean 的名称或id进行属性注入,需要用 @Autowired 和 @Qualifier 一起使用

实际开发中,使用 @Resource(name=" ") 来进行按照对象的名称完成属性注入

3.其他注解

@PostConstruct 相当于 init-method,用于初始化函数的注解

@PreDestroy 相当于 destroy-method,用于销毁函数的注解

@Scope 作用范围的注解,常用的是默认单例,还有多例 @Scope(“prototype”)

IOC 的 XML 和注解开发比较

适用场景:XML 适用于任何场景;注解只适合自己写的类,不是自己提供的类无法添加注解。

可以使用 XML 管理 bean,使用注解来进行属性注入

AOP开发

AOP 是 Aspect Oriented Programming 的缩写,意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,是OOP的延续。

AOP 能够对程序进行增强,在不修改源码的情况下,可以进行权限校验,日志记录,性能监控,事务控制等。

也就是说功能分为两大类,一类是核心业务功能,一类是辅助增强功能。两类功能彼此独立进行开发。比如登录功能是核心业务功能,日志功能是辅助增强功能,如果有需要,将日志和登录编制在一起。辅助功能就称为切面,这种能选择性的、低耦合的把切面和核心业务功能结合的编程思想称为切面编程。

底层实现

JDK 动态代理只能对实现了接口的类产生代理。Cglib 动态代理可以对没有实现接口的类产生代理对象,生成的是子类对象。

使用 JDK 动态代理:

public interface UserDao {

public void insert();

public void delete();

public void update();

public void query();

}

实现类:

public class UserDaoImpl implements UserDao {

@Override

public void insert() {

System.out.println(“insert”);

}

@Override

public void delete() {

System.out.println(“delete”);

}

@Override

public void update() {

System.out.println(“update”);

}

@Override

public void query() {

System.out.println(“query”);

}

}

JDK 代理:

public class JDKProxy implements InvocationHandler{

private UserDao userDao;

public JDKProxy(UserDao userDao){

this.userDao=userDao;

}

public UserDao createProxy(){

UserDao userDaoProxy=(UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(),

userDao.getClass().getInterfaces(), this);

return userDaoProxy;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if(“update”.equals(method.getName())){

System.out.println(“权限校验”);

return method.invoke(userDao, args);

}

return method.invoke(userDao, args);

}

}

通过动态代理增强了 update 函数。 测试类:

public class Demo1 {

@Test

public void demo1(){

UserDao userDao=new UserDaoImpl();

UserDao proxy=new JDKProxy(userDao).createProxy();

proxy.insert();

proxy.delete();

proxy.update();

proxy.query();

}

}

运行结果为:

insert

delete

权限校验

update

query

CglibCglib 是第三方开源代码生成类库,可以动态添加类的属性和方法。

与上边JDK代理不同,Cglib的使用方式如下:

public class CglibProxy implements MethodInterceptor{

//传入增强的对象

private UserDao customerDao;

public CglibProxy(UserDao userDao){

this.userDao=userDao;

}

public UserDao createProxy(){

Enhancer enhancer=new Enhancer();

enhancer.setSuperclass(userDao.getClass());

enhancer.setCallback(this);

UserDao proxy=(UserDao)enhancer.create();

return proxy;

}

@Override

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

if(“save”.equals(method.getName())){

System.out.println(“enhance function”);

return methodProxy.invokeSuper(proxy, args);

}

return methodProxy.invokeSuper(proxy, args);

}

}

如果实现了接口的类,底层采用JDK代理。如果不是实现了接口的类,底层采用 Cglib代理。

IOC与传统方式的比较

获取对象方式:传统通过 new 关键字主动创建一个对象。IOC 方式中,将对象的生命周期交给 Spring 管理,直接从 Spring 获取对象。也就是控制反转————将控制权从自己手中交到了 Spring 手中。

Spring 的 AOP 开发(AspectJ 的 XML 方式)

AspectJ 是一个 AOP 的框架,Spring 引入 AspectJ,基于 AspectJ 进行 AOP 的开发。

相关术语

Joinpoint: 连接点,可以被拦截到的点。也就是可以被增强的方法都是连接点。

Pointcut: 切入点,真正被拦截到的点,也就是真正被增强的方法

Advice: 通知,方法层面的增强。对某个方法进行增强的方法,比如对 save 方法进行权限校验,权限校验的方法称为通知。

Introduction: 引介,类层面的增强。

Target: 目标,被增强的对象(类)。

Weaving: 织入,将 advice 应用到 target 的过程。

Proxy: 代理对象,被增强的对象。

Aspect: 切面,多个通知和多个切入点的组合。

使用方法

引入相关包

引入配置文件

<?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:aop=“http://www.springframework.org/schema/aop” xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

编写目标类并配置:

public class ProductDaoImpl implements ProductDao {

@Override

public void save() {

System.out.println(“save”);

}

@Override

public void update() {

System.out.println(“update”);

}

@Override

public void find() {

System.out.println(“find”);

}

@Override

public void delete() {

System.out.println(“delete”);

}

}

编写切面类,假设用于权限验证并配置

public class MyAspectXML {

public void checkPri(){

System.out.println(“check auth”);

}

}

通过AOP配置完成对目标类的增强

aop:config

<aop:pointcut expression=“execution(* demo1.ProductDaoImpl.save(…))” id=“pointcut1”/>

<aop:aspect ref=“myAspect”>

<aop:before method=“chechPri” pointcut-ref=“pointcut1”/>

</aop:aspect>

</aop:config>

通知类型

前置通知:在目标方法执行前操作,可以获得切入点信息

<aop:before method=“chechPri” pointcut-ref=“pointcut1”/>

public void checkPri(JoinPoint joinPoint){

System.out.println("check auth "+joinPoint);

}

后置通知:在目标方法执行后操作,可以获得方法返回值

<aop:after-returning method=“writeLog” pointcut-ref=“pointcut2” returning=“result”/>

public void writeLog(Object result){

System.out.println("writeLog "+result);

}

环绕通知:在目标方法执行前和后操作,可以阻止目标方法执行

<aop:around method=“around” pointcut-ref=“pointcut3”/>

public Object around(ProceedingJoinPoint joinPoint) throws Throwable{

System.out.println(“before”);

Object result=joinPoint.proceed();

System.out.println(“after”);

return result;

}

异常抛出通知:程序出现异常时操作

<aop:after-throwing method=“afterThrowing” pointcut-ref=“pointcut4” throwing=“ex”/>

public void afterThrowing(Throwable ex){

System.out.println("exception "+ex.getMessage());

}

最终通知:相当于finally块,无论代码是否有异常,都会执行

<aop:after method=“finallyFunc” pointcut-ref=“pointcut4”/>

public void finallyFunc(){

System.out.println(“finally”);

}

引介通知:不常用

Spring 切入点表达式

基于 execution 函数完成

语法:[访问修饰符] 方法返回值 包名.类名.方法名(参数)

其中任意字段可以使用*代替表示任意值

Spring 的 AOP 基于 AspectJ 注解开发

开发步骤

引入jar包

设置配置文件:

<?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:aop=“http://www.springframework.org/schema/aop”

xmlns:tx=“http://www.springframework.org/schema/tx”

xsi:schemaLocation="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.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx.xsd">

编写配置目标类

public class OrderDao {

public void save(){

System.out.println(“save order”);

}

public void update(){

System.out.println(“update order”);

}

public void delete(){

System.out.println(“delete order”);

}

public void find(){

System.out.println(“find order”);

}

}

开启aop注解自动代理

aop:aspectj-autoproxy/

编写切面类并配置

@Aspect

public class MyAspectAnno {

@Before(value=“execution(* demo1.OrderDao.save(…))”)

public void before(){

System.out.println(“before”);

}

}

注解通知类型

@Before: 前置通知

@AfterReturning: 后置通知

@AfterReturning(value=“execution(* demo1.OrderDao.save(…))”,returning=“result”)

public void after(Object result){

System.out.println("after "+result);

}

@Around:环绕通知

@Around(value=“execution(* demo1.OrderDao.save(…))”)

public Object around(ProceedingJoinPoint joinPoint) throws Throwable{

System.out.println(“before”);

Object obj=joinPoint.proceed();

System.out.println(“after”);

return obj;

}

@AfterThrowing: 抛出异常

@AfterThrowing(value=“execution(* demo1.OrderDao.save(…))”,throwing=“e”)

public void afterThrowing(Throwable e){

System.out.println(“exception:”+e.getMessage();

}

@After: 最终通知

@After(value=“execution(* demo1.OrderDao.save(…))”)

public void after(){

System.out.println(“finally”);

}

@PointCut:切入点注解

@PointCut(value=“execution(* demo1.OrderDao.save(…))”)

private void pointcut1(){}

此时,在上述通知的注解中,value可以替换为该函数名,例如:

@After(value=“MyAspect.pointcut1()”)

public void after(){

System.out.println(“finally”);

}

这个注解的好处是,只需要维护切入点即可,不用在修改时修改每个注解。

Spring 的 JDBC 模板

Spring 对持久层也提供了解决方案,也就是 ORM 模块和 JDBC 的模板。针对 JDBC ,提供了 org.springframework.jdbc.core.JdbcTemplate 作为模板类。

使用 JDBC 模板

引入jar包,数据库驱动,Spring 的 jdbc 相关包。

基本使用:

public void demo1(){

//创建连接池

DriverManagerDataSource dataSource=new DriverManagerDataSource();

dataSource.setDriverClassName(“com.mysql.jdbc.Driver”);

dataSource.setUrl(“jdbc:mysql:///spring4”);

dataSource.setUsername(“root”);

dataSource.setPassword(“123456”);

//创建JDBC模板

JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);

jdbcTemplate.update(“insert into account values (null,?,?)”, “xiaoming”,1000d);

}

将连接池和模板交给 Spring 管理

配置文件:

测试文件:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(“classpath:applicationContext.xml”)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

分享一些系统的面试题,大家可以拿去刷一刷,准备面试涨薪。

这些面试题相对应的技术点:

  • JVM
  • MySQL
  • Mybatis
  • MongoDB
  • Redis
  • Spring
  • Spring boot
  • Spring cloud
  • Kafka
  • RabbitMQ
  • Nginx

大类就是:

  • Java基础
  • 数据结构与算法
  • 并发编程
  • 数据库
  • 设计模式
  • 微服务
  • 消息中间件

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
g 管理

配置文件:

测试文件:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(“classpath:applicationContext.xml”)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-sdggcmX0-1713425354061)]

[外链图片转存中…(img-jTlMfH2u-1713425354062)]

[外链图片转存中…(img-djcfhq5P-1713425354062)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

分享一些系统的面试题,大家可以拿去刷一刷,准备面试涨薪。

这些面试题相对应的技术点:

  • JVM
  • MySQL
  • Mybatis
  • MongoDB
  • Redis
  • Spring
  • Spring boot
  • Spring cloud
  • Kafka
  • RabbitMQ
  • Nginx

大类就是:

  • Java基础
  • 数据结构与算法
  • 并发编程
  • 数据库
  • 设计模式
  • 微服务
  • 消息中间件

[外链图片转存中…(img-FWAiOCvH-1713425354063)]

[外链图片转存中…(img-xAgvnqOa-1713425354063)]

[外链图片转存中…(img-XH9hE3sc-1713425354063)]

[外链图片转存中…(img-PtNdWxS0-1713425354063)]

[外链图片转存中…(img-GL0IGmOZ-1713425354064)]

[外链图片转存中…(img-sGRxCKDO-1713425354064)]

[外链图片转存中…(img-4ER2qybq-1713425354064)]

[外链图片转存中…(img-0YZs4JFI-1713425354064)]

[外链图片转存中…(img-ui2RQCKi-1713425354065)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值