内容较多,建议根据目录梳理食用
文章目录
Spring版本
版本区别
-
GA:General Availability,正式发布版,最稳定版本。
-
PRE:release,预览版,内部测试版。
-
SNAPSHOT:快照版,可以使用,但仍在继续改进。
-
ALPHA:内测版。
-
BETA:公测版。
-
RELEASE:正式版。
-
CURRENT:当前推荐的版本。
版本标号
主版本号.子版本号.修正版本号
基础知识
框架构图
ApplicationContext常用的的实现类
new FileSystemXmlApplicationContext("");
new ClassPathXmlApplicationContext("");
使用第一个实现类加载配置文件要输入xml文件全路径
使用第二个实现类就是当前类路径
IOC
-
IOC思想是基于IOC容器完成,IOC容器底层就是对象工厂。
-
Spring提供的IOC容器两种方式:(主要就是两个接口)
第一种是BeanFactory:是Spring内自己使用的接口,加载配置文件的时候不会去创建对象,只有在获取的时候才会去创建。
第二种是ApplicationContext:BeanFactory的子接口。
FactoryBean
Spring有两种Bean,第一种是自己常见的Bean,另外一种是工厂Bean(FactoryBean)。即:普通Bean定义的class全类名和返回类的类型相同,工厂Bean返回可以不相同。
建立工厂Bean需要该类实现FactoryBean接口:
import org.springframework.beans.factory.FactoryBean;
//在接口上加上泛型就可以实现返回指定类型对象
public class MyFactoryBean implements FactoryBean {
@Override
public boolean isSingleton() { return FactoryBean.super.isSingleton(); }
@Override
public Object getObject() throws Exception { return null; }
@Override
public Class<?> getObjectType() { return null; }
}
Bean的生命周期
- 创建Bean,即构造器。
- 设置Bean的属性和对其他Bean的引用,如:set方法。
- 调用Bean的初始化的方法,需要配置。
- Bean可以被使用。
- 当容器在关闭时,调用销毁Bean的方法,需要配置。
加入Bean的后置处理器后,声明周期增加了两步骤:
- 初始化前,把Bean实例传给后置处理器的postProcessBeforeInitialization方法。
- 初始化后,把Bean实例传给后置处理器的postProcessAfterInitialization方法。
后置处理器的创建方式:
public class MyBeanPost implements BeanPostProcessor {}
//重写接口的两个方法后,在配置文件中添加这个类的Bean,spring可以自动识别
XML方式管理Bean
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
命名空间
-
p命名空间
p命名空间主要是用于简化属性的注入。在Spring的xml文件约束中加入如下约束:
xmlns:p="http://www.springframework.org/schema/p"
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="Bean id" class="全类名" p:属性="值"></bean> </beans>
-
util命名空间
util命名空间主要可以提取集合,方便xml中重复使用该集合。
xmlns:util="http://www.springframework.org/schema/util" http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 提取List集合,使用时ref="id"即可 --> <util:list id=""> <value>值</value> <value>值</value> <value>值</value> </util:list> </beans>
-
context命名空间:常用在包扫描
-
aop命名空间:生成代理对象
创建Bean
基于无参构造进行创建,有参构造方式参见依赖注入
<bean id="对象标识" class="全类名" scope="prototype" init-method="无括号的初始化方法名" destroy-method="无括号的销毁方法名"></bean>
<!-- scope默认单实例(singleton),scope="prototype"为多实例 -->
<!-- scope值还有:request session 生成的对象会放到相对应作用域里 -->
<!-- 初始化方法自动调用 -->
<!-- 销毁方法使用Application的子类内的close方法,需要手动调用 -->
<!-- name:和id相似,name可以使用特殊符号,是为Struts准备的 -->
注入属性
通过DI(依赖注入)实现
注入属性的方法
-
set方法注入
<bean id="对象标识" class="全类名"> <property name="属性" value="需要注入的值"></property> </bean>
-
有参构造注入
<bean id="对象标识" class="类全名"> <constructor-arg name="对象的属性名" value="值"></constructor-arg> </bean>
-
P命名空间注入(主要可以简化xml配置)
p命名空间其本质是使用set方法注入,因此bean类还需要无参构造和set方法。
<!-- 在xml中加入约束后就能直接使用p命名空间 --> <bean id="xx" class="**" p:xx="**"></bean>
各种属性的注入方式
<bean id="对象标识" class="全类名">
<!----------- 注入字面量 ----------->
<property name="属性" value="需要注入的值"></property>
<property name="属性">
<value>需要注入的值</value>
</property>
<!----------- 注入外部Bean ----------->
<property name="属性" ref="被注入类的id"></property>
<!----------- 注入内部Bean ----------->
<property name="属性名">
<!-- Bean结构和beans内相同 -->
<bean id="可以没有id" class="全类名">
<property name="属性" value="值"></property>
</bean>
</property>
<!----------- 级联赋值,需要属性的get方法 ----------->
<property name="属性.属性" value="值"></property>
<!----------- 集合类型 ----------->
<!-- 数组类型 -->
<property name="属性">
<array>
<value>值</value>
<value>值</value>
</array>
</property>
<!-- List集合 -->
<property name="属性">
<list>
<value>值</value>
<!-- 或者 -->
<ref>Bean对象id</ref>
</list>
</property>
<!-- Map集合 -->
<property name="属性">
<map>
<entry key="键" value="值"></entry>
<entry key="键" value="值"></entry>
</map>
</property>
<!-- Set集合 -->
<property name="属性">
<set>
<value>值</value>
<value>值</value>
</set>
</property>
<!----------- 设置值为null ----------->
<property name="属性名"><null/></property>
<!----------- 特殊字符(左右尖括号) ----------->
<!----------- 可以使用CDATA,也可以直接转义:<> ----------->
<property name="属性名">
<value><![CDATA[*******]]></value>
</property>
</bean>
自动装配
<bean id="对象标识" class="全类名" autowire=""></bean>
<!-- autowire有两个属性:byName根据属性名自动注入,byType根据属性类型自动注入 -->
<!-- byName需要Bean的id和类名相同 -->
<!-- byType方式中,相同类型的Bean不能定义多个 -->
引入外部文件
常用的地方如:数据库连接配置
引入外部properties:
<?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 http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入外部文件 -->
<context:property-placeholder location="classpath:文件名"/>
<!-- 使用 -->
<bean id="对象标识" class="全类名">
<property name="属性名" value="${key}"></property>
</bean>
</beans>
注解方式管理Bean
四个注解作用相同,对应层使用对应注解,有利于逻辑清晰。
@Component:Bean管理
@Service:Service层
@Controller:Controller层
@Repository:持久层
使用注解需要引入aop的jar包,之后开启组件扫描:
<!-- 引入context命名空间 -->
<?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 http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启组件扫描 -->
<context:property-placeholder location="classpath:文件名"/>
<!--
注入属性
@AutoWired:根据类型自动注入
@Qualifier:根据属性名称注入
@Resource:可以根据类型和名称注入,但是Spring不推荐使用,因为该注解是javax包内的
@Value:注入字面量
import javax.annotation.Resource;
@Component
public class Demo {
//类型自动注入
@Autowired
private User user1;
//名称自动注入,主要可以解决接口实现类的注入
@Autowired
@Qualifier(value = "users")
private User user2;
//类型注入
@Resource
private User user3;
//名称注入
@Resource(name = "users")
private User user4;
@Value("使用@Value注入str的值")
private String str;
public void test(){
System.out.println(user1+"1使用@Autowired类型注入");
System.out.println(user2+"2使用@Qualifier名称注入");
System.out.println(user3+"3使用@Resource类型注入");
System.out.println(user4+"4使用@Resource名称注入");
System.out.println("str = " + str);
}
}
//名称可以忽略不写,默认首字母小写,重复的类报错修改Bean的id
@Component(value = "users")
class User{
@Override
public String toString() {return "user";}
}
/* 测试类 */
/* Applica.xml中开启了注解扫描 */
public class Tests {
@Test
public void DemoTest(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Applica.xml");
Demo demo = applicationContext.getBean("demo",Demo.class);
demo.test();
}
}
完全注解开发
使用配置类替换xml文件
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "xyz.qnhj.ioc")
public class SpringConfig { }
/* 测试类 */
public class Tests {
@Test
public void SpringConfigTest(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Demo demo = (Demo)context.getBean("demo");
demo.test();
}
}
AOP
面向切面编程底层使用了动态代理,动态代理分两种:
-
有接口情况,JDK动态代理
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKProxy { public static void main(String[] args) { DaoImpl daoImpl = new DaoImpl(); /* 第一个参数:加载代理对象的类加载器 第二个参数:动态代理类需要实现的接口 Class[]类型 第三个参数:动态代理执行类,会调用里面的invoke方法去执行 */ Dao dao = (Dao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),new Class[]{Dao.class},new DaoProxy(daoImpl)); int add = dao.add(1, 2); System.out.println("add = " + add); dao.updata("测试文本"); } } //代理类,即增强部分 class DaoProxy implements InvocationHandler{ private Object object; public DaoProxy(Object object) { this.object = object; } //增强的逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method.getName()+"方法执行前……"); Object ref = method.invoke(object,args); System.out.println(method.getName()+"方法执行完成……"); return ref; } } //接口 interface Dao{ int add(int a,int b); void updata(String id); } //接口的实现类 class DaoImpl implements Dao{ @Override public int add(int a, int b) { System.out.println("add方法执行"); return a+b; } @Override public void updata(String id) { System.out.println("删除:" + id+"方法执行"); } }
-
没有接口情况,CGLIB动态代理
AOP中的概念
-
连接点:可以被增强的方法
-
切入点:实际中被增强的方法
-
通知(增强):增强的逻辑部分
通知的五种类型:
- 前置通知:方法前执行
- 后置通知:方法后执行
- 环绕通知:方法前后执行
- 异常通知:方法出现异常后执行
- 最终通知:类似finally
-
切面:把通知应用到切入点的过程动作
切入点表达式
execution(权限修饰符、返回值类型、类的全路径、方法名称(参数列表)),如:
execution(* com.Demo.add(…))
execution(* com.Demo.*(…))
AspectJ
Spring一般基于AspectJ实现AOP,AspectJ不是Spring的组成部分,是一个独立的AOP框架,一般会把AspectJ和Spring一起使用,进行AOP操作。
基于注解方式
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
//增强方法 这里面增强方式五种注解
@Component
@Aspect
public class Demo {
@Before(value = "execution(* 包名.User.add(..))")
public void before(){
System.out.println("前置通知");
}
}
import org.springframework.stereotype.Component;
//被增强方法
@Component
public class User{
public void add(){
System.out.println("user...do...");
}
}
<?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"
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">
<!-- 开启扫描 -->
<context:component-scan base-package="包名"></context:component-scan>
<!-- 生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
//测试类
public class Tests {
@Test
public void springAopOneTest(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("App.xml");
User user = applicationContext.getBean("user", User.class);
user.add();
}
}
基于配置文件(不常用)
public class User {
public void doSame(){
System.out.println("user方法执行了");
}
}
public class Demo {
public void before(){
System.out.println("前置通知");
}
}
<?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">
<bean class="增强类" id="demo"></bean>
<bean class="被增强类" id="user"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut id="p" expression="execution(* 包名.User.doSame(..))"/>
<!-- 定义切面 -->
<aop:aspect ref="demo">
<!-- method:增强逻辑所在的方法 pointcut-ref:增强哪一个切入点 -->
<!-- 其他通知相同 -->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
</beans>
@Test
public void springAopXmlTest(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("AppAopXml.xml");
User user = applicationContext.getBean("user",User.class);
user.doSame();
}
完全注解
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = {"包名"})
@EnableAspectJAutoProxy(exposeProxy = true) //开启自动扫描
public class AopConfig {
}
/* 测试类 */
public class Tests {
@Test
public void SpringConfigTest(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
User user = applicationContext.getBean("user",User.class);
user.doSame();
}
}
公共切入点
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Demo {
//抽取切入点
@Pointcut(value = "execution(* 包名.User.add(..))")
public void pointDemo(){
}
@Before(value = "pointDemo()")
public void before(){
System.out.println("前置通知");
}
}
多个增强类
多个增强方法设置先后执行顺序,只需要在增强方法上面添加@Order(数字)
,数字越小,优先级越高,最高为0。
备注
jar包坐标
<!-- IOC部分 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- AOP新增部分 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
版本
Spring版本:5.2.6.RELEASE