Spring5框架 笔记总结
Posted IT_Holmes
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring5框架 笔记总结相关的知识,希望对你有一定的参考价值。
文章目录
1. 使用Java 的方式配置Spring
我们不完全使用Spring的xml来配置,我们使用Java代码的方式来操作。
JavaConfig是Spring的一个子项目,在Spring 4之后,他成为了一个核心功能!
通过 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 来获取容器context,对应的情况不同!
前者是通过Spring和xml方式来获取的,后者是通过部分Spring注解和Java代码获取的!
代码如下:
User.java代码(实体类):
package com.itholmes.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//此时@Component注解的意思,就是说明这个类被Spring接管了,注册到容器中。
@Component
public class User
private String name;
public String getName()
return name;
@Value("itholmes")//属性注入值,也可以在set方法上面。
public void setName(String name)
this.name = name;
@Override
public String toString()
return "User" +
"name='" + name + '\\'' +
'';
config层下的HolmesConfig.java配置类:
一定记住配置类中几个注解的使用!
package com.itholmes.config;
import com.itholmes.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//@Configuration注解也会被Spring容器托管,注册到容器中,因为它本身也包含了@Component注解。
//@Configuration代表这是一个配置类,就和我们之前的beans.xml文件是一样的。
@Configuration
@ComponentScan("com.itholmes.pojo")//同样也可以通过@ComponentScan,在这里进行一个扫描操作。
@Import(HolmesConfig2.class)//@Import注解,将相应的配置文件导入当前,也就是合并的效果。
public class HolmesConfig
//注册一个bean,就相当于我们之前写的一个bean标签。
//该方法的名字getUser就是相当于bean标签中的id属性。
//这个方法的返回值,就相当于bean标签中的class属性。
@Bean
public User getUser()
return new User();//就是返回值,要注入到bean中的对象。
模拟导入HolmesConifg配置类的配置类2:
package com.itholmes.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HolmesConfig2
测试类:
一定牢记测试类中的AnnotationConfigApplicationContext(HolmesConfig.class);作用!
/*
概述:
@Date:Create in 14:45 2021/12/30
*/
import com.itholmes.config.HolmesConfig;
import com.itholmes.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest
public static void main(String[] args)
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载。
ApplicationContext context = new AnnotationConfigApplicationContext(HolmesConfig.class);
User user = context.getBean("getUser", User.class);
System.out.println(user.getName());
这种纯java的配置方式,在Spring Boot中随处可见。
2. 代理模式
Java的23种设计模式之一的代理模式,很重要,因为它是Spring SOP的底层内容。
代理模式的分类:
- 静态代理。
- 动态代理。
平时,我们学习中操作的都是静态代理模式,定义一个接口,一个用户,一个代理角色,一个厂家。用户通过代理来获取操作厂家提供资源的一个效果。
纵向开发 和 横向开发的效果图:
3. 动态代理 简述
简而言之,动态代理,在代理模式的情况下,它是自动生成代理类。
动态代理的描述:
- 动态代理的底层都是通过反射来实现的。
- 动态代理的代理类是动态生成的,不是我们直接写好的!
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理。
- 基于接口动态代理机制:JDK动态代理(也是默认的)。
- 基于类的动态代理机制:cglib动态代理。
- java字节码实现:Javassist。
Spring AOP是基于动态代理的,基于两种动态代理机制:JDK动态代理(也是默认的)和CGLIB动态代理。
需要了解两个类:Proxy (代理),InvocationHandler (调用处理程序)。
InvocationHandler是java.lang.reflect反射包下的一个接口:
Proxy 是java.lang.reflect反射包下的一个类:
proxy类对应的4个静态方法:
4. 动态代理的使用
Rent接口:
package com.itholmes.demo3;
public interface Rent
void rent();
Host类(房东):
package com.itholmes.demo3;
public class Host implements Rent
@Override
public void rent()
System.out.println("房东要出租房子!");
ProxyInvocationHandler.java实现InvocationHandler接口的类,这个类可以自动生成代理类。
package com.itholmes.demo3;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//我们会用这个类自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler
//被代理的接口
private Rent rent;
public void setRent(Rent rent)
this.rent = rent;
//生成得到代理类
//第一个参数,类构造器:this.getClass().getClassLoader()加载到代理类在那个位置。
//第二个参数,得到实现rent的接口:rent.getClass().getInterfaces()表示它要代理的接口是哪一个接口。
//第三个参数,实现InvocationHandler的类,这里我们本身就实现了InvocationHandler了,所以用this就可,。
public Object getProxy()
Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
//System.out.println("判断o:"+o);
return o;
//上面的Proxy.newProxyInstance()方法执行后,会执行当前的invoke方法来处理代理实例,并返回结果。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
seeHouse();
//动态代理的本质,就是使用反射机制实现的!
Object invoke = method.invoke(rent, args);
//System.out.println("判断invoke:"+invoke);
fare();
return invoke;
//我们可以通过打印来判断这里的invoke对象和上面的o对象是一个对象么?
//invoke:com.itholmes.demo3.Host@2b193f2d
//getProxy:com.itholmes.demo3.Host@2b193f2d
//返回结果不难看出就是一个对象。
public void seeHouse()
System.out.println("中介带看房子");
public void fare()
System.out.println("中介收费");
Client用户测试类:
package com.itholmes.demo3;
public class Client
public static void main(String[] args)
//真实角色(房主)
Host host = new Host();
//代理角色(中介):现在没有
ProxyInvocationHandler handler = new ProxyInvocationHandler();
//通过调用程序处理角色(当前我们定义的ProxyInvocationHandler类)来处理我们要调用的接口对象。
handler.setRent(host);
Rent proxy = (Rent)handler.getProxy();//这里的proxy就是动态生成的!
proxy.rent();
此外,invoke中的method方法可以调用很多方法,例如:
method.getName()获取名字等等。
5. Spring AOP
面向对象程序设计(Object Oriented Programming , OOP)
面向切面编程:(Aspect Oriented Programming , AOP)
AOP是OOP的延续。
AOP的一个效果图如下:
SpringAOP中,通过Advice定义横切逻辑。
在Spring中支持5种类型的Advice:
6. 实现aop(一) 通过SpringAPI接口实现(围绕接口来实现)
实现AOP前,需要一个织入依赖包aspectjweaver!
导入完包后,要导入响应的约束和支持约束条件:
其实不管什么约束条件都是差不多的格式,稍微改改字母就能修改。
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd"
上面准备工作完成后,我们创建两个类分别实现了AfterReturningAdvice 和 MethodBeforeAdvice接口:
log类实现MethodBeforeAdvice方法执行前调用它:
package com.itholmes.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice
//before方法的参数:
//method:要执行的目标对象的方法
//objects:参数
//o:目标对象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
AfterLog类,调用AfterReturningAdvice接口,负责执行方法执行后的内容:
package com.itholmes.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice
//returnValue:使用AfterReturningAdvice是可以拿到一个returnValue返回值的。
//其他的参数和BeforeAdvice中的before参数一样。
@Override
public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable
System.out.println("执行了"+method.getName()+"方法,返回结构为:"+returnValue);
UserService接口:
package com.itholmes.service;
public interface UserService
public void add();
public void delete();
public void update();
public void select();
UserServiceImpl实现类:
package com.itholmes.service;
public class UserServiceImpl implements UserService
@Override
public void add()
System.out.println("增加了一个用户");
@Override
public void delete()
System.out.println("删除了一个用户");
@Override
public void update()
System.out.println("更新了一个用户");
@Override
public void select()
System.out.println("查询了一个用户");
再往后,先在xml文件中,注册bean,然后通过xml方式来指定aop的相关内容了。
创建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: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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.itholmes.service.UserServiceImpl"/>
<bean id="log" class="com.itholmes.log.Log"/>
<bean id="afterLog" class="com.itholmes.log.AfterLog"/>
<!--上面的AOP约束一定要导入!-->
<!--配置AOP:需要导入aop的约束-->
<!--方式一:使用原生的Spring API接口-->
<aop:config>
<!--切入点: expression:表达式 , execution(要执行的位置! * * * *) *在这代表的是所有的意思。-->
<!--execution()方法参数含义下面会说到!-->
<aop:pointcut id="pointcut" expression="execution(* com.itholmes.service.UserServiceImpl.*(..))"></aop:pointcut>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
最后,我们测试一下mytest类:
import com.itholmes.service.UserService;
import com.itholmes.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest
public static void main(String[] args)
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//注意:AOP实现原理是动态代理,而动态代理代理的是接口,因此在这我们只能写接口类型。
UserService userService = (UserService) context.getBean("userService");
userService.add();
7. execution()方法参数含义
先说一下execution()方法参数的含义。
execution()是最常用的切点函数,其语法如下所示:
整个表达式可以分为五个部分:
- execution(): 表达式主体。
- 第一个*号:表示返回类型,*号表示所有的类型。
- 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
- 第二个*号:表示类名,*号表示所有的类。
- *(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
这些参数理解了才更容易理解AOP。
8. 实现aop(二) 自定义类方式 (围绕自定义类,也就是切面(aspect)定义来实现)
测试类,接口,接口实现类不变。
首先,创建一个自定义类:
package com.itholmes.diy;
public class DiyPointCut
public void before()
System.out.println("------方法执行前-------");
public void after()
System.out.println("-------方法执行后--------");
xml配置文件来进行配置:
其实就是换了aop: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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.itholmes.service.UserServiceImpl"/>
<bean id="log" class="com.itholmes.log.Log"/>
<bean id="afterLog" class="com.itholmes.log.AfterLog"/>
<!--方式二:通过自定义类方式实现-->
<bean id="diy" class="com.itholmes.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面: ref指定要引用的类-->
<aop:aspect ref="diy"Spring5框架 笔记总结