Spring5 基础学习
下载Spring5
下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring/
简单测试
public class User {
public void add(){ System.out.println("hello"); } } ############################################ <?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">
<!-- 配置user对象创建--> <bean id="user" class="com.miao.testspring5.User"></bean> </beans> ################################################# public class TestSpring5 {
@Test public void testUser(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); User user=context.getBean("user",User.class); System.out.println(user); user.add(); } }
|
IOC容器
IOC底层原理
IOC概念
- 控制反转,把对象创建和对象之间的调用过程,交给spring管理
- 使用IOC目的:为了降低耦合度
IOC底层原理
xml解析、工厂模式、反射
简单图解
IOC接口(BeanFactory)
IOC容器底层是 对象工厂
Spring 提供IOC容器实现的两种方式:(接口)
BeanFactory:IOC容器基本实现,是spring内部的使用接口
加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
ApplicationContext:BeanFactory接口的子接口,功能更强大
加载配置文件时候就会将配置文件中的对象进行创建
ApplicationContext:两个实现类
IOC操作Bean管理(基于xml)
基于xml方式创建对象
在spring配置文件中,使用bean标签,标签里面添加对应属性,
就可以实现对象创建。
在bean标签中有很多属性,常用属性:
- id属性:唯一标识
- class属性:类全路径(包类路径)
创建对象的时候,默认执行无参数构造方法完成对象创建
基于xml方式注入属性
- DI:依赖注入,注入属性
- 方式一:使用set方法注入
- 方式二:使用有参构造注入
使用set方法注入属性
public class Book { private String name; private String author; public void setName(String name) { this.name = name; } public void setAuthor(String author) { this.author = author; } public void testDemo(){ ...... } } ########################################### # bean.xml中 <!-- set方法注入属性--> <bean id="book" class="com.miao.testspring5.Book"> <!-- name:类里面属性名称 value:向属性注入值 --> <property name="name" value="葵花宝典"></property> <property name="author" value="东方不服"></property> </bean> ############################################### @Test public void testBook(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Book book=context.getBean("book",Book.class); System.out.println(book); book.testDemo(); }
|
使用有参构造注入属性
public class Order { private String name; private String address;
public Order(String name, String address) { this.name = name; this.address = address; } public void testDemo(){ System.out.println(name+"---------"+address); } } ########################################## <!-- 配置order对象有参构造注入属性--> <bean id="order" class="com.miao.testspring5.Order"> <constructor-arg name="name" value="马桶"></constructor-arg> <constructor-arg name="address" value="made in china"></constructor-arg> </bean> ########################################### @Test public void testOrder(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Order order=context.getBean("order",Order.class); System.out.println(order); order.testDemo();
}
|
P标签 set注入属性(了解)
注入其它类型属性
null值
<!--注入空值--> <bean id="book" class="com.miao.testspring5.Book"> <property name="name" value="葵花宝典"></property> <property name="author" value="东方不服"></property> <property name="address"> <null></null> </property> </bean>
|
属性值包含特殊符号
<!-- 属性值包含特殊含义 1.把<>进行转义 < > 2.特殊内容写到 CDATA中 --> <bean id="book" class="com.miao.testspring5.Book"> <property name="name" value="葵花宝典"></property> <property name="author" value="东方不服"></property> <property name="address"> <value> <![CDATA[ <<中国的宝贝>> ]]> </value> </property> </bean>
|
注册属性-外部bean
<!-- 配置UserService和UserDao对象创建--> <bean id="userService" class="com.miao.inner.service.UserService"> <!-- name属性:类 里面的属性名称 ref属性:创建UserDao对象 bean标签 id值--> <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="com.miao.inner.dao.UserDaoImpl"></bean> ####################################### public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) { this.userDao = userDao; }
public void add(){ System.out.println("service add ----------"); userDao.update(); } } ################################################## public interface UserDao { public void update(); } ################################################### public class UserDaoImpl implements UserDao{ @Override public void update() { System.out.println("dao update -------"); } } ###################################################### @Test public void testUser(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); UserService userService=context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); }
|
注入属性-内部bean和级联关系
@Test public void testBean(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Emp emp=context.getBean("emp", Emp.class); System.out.println(emp); emp.add(); } ############################### public class Dept { private String dname;
public void setDname(String dname) { this.dname = dname; } public String toString(){ return "我的部门是"+dname; } } #######################################
public class Emp { private String ename; private String egender; private Dept dept;
public void setDept(Dept dept) { this.dept = dept; }
public void setEname(String ename) { this.ename = ename; }
public void setEgender(String egender) { this.egender = egender; } public void add(){ System.out.println(ename+"--"+egender+"--"+dept); } } ######################################### <!-- 配置Dept部门和 Emp员工对象创建-->
<!-- 内部bean--> <bean id="emp" class="com.miao.bean.Emp"> <!-- 对象属性--> <property name="dept" > <bean id="dept" class="com.miao.bean.Dept"> <property name="dname" value="销售"></property> </bean> </property> <!-- 普通属性--> <property name="ename" value="张三"></property> <property name="egender" value="nan"></property> </bean>
|
注入属性-级联
注入属性-数组类型-集合类型
public class Stu { private String[] cources; private List<String> list; private Map<String,String> maps; private Set<String> set;
public void setCources(String[] cources) { this.cources = cources; }
public void setList(List<String> list) { this.list = list; }
public void setMaps(Map<String, String> maps) { this.maps = maps; }
public void setSet(Set<String> set) { this.set = set; } public void test(){ System.out.println(Arrays.toString(cources)); System.out.println(list); System.out.println(maps); System.out.println(set); } } ####################################################### <!--对象注入--> <bean id="stu" class="com.miao.collection.Stu"> <!-- 数组属性注入--> <property name="cources"> <array> <value>java</value> <value>nodejs</value> </array> </property> <!-- 集合属性注入--> <property name="list"> <list> <value>html</value> <value>javascript</value> </list> </property> <property name="set"> <set> <value>vue</value> <value>vue3.0</value> </set> </property> <property name="maps"> <map> <entry key="Hexo" value="hexo"></entry> <entry key="Php" value="php"></entry> </map> </property> </bean> #####################################################
|
注入对象属性 在集合中
<!--对象注入--> <bean id="stu" class="com.miao.collection.Stu"> <property name="courseList"> <list> <ref bean="course"></ref> <ref bean="course1"></ref> </list> </property> </bean> <bean id="course" class="com.miao.collection.Course"> <property name="cname" value="剑术"></property> </bean> <bean id="course1" class="com.miao.collection.Course"> <property name="cname" value="太极"></property> </bean> ######################################## private List<Course> courseList; public void setCourseList(List<Course> courseList) { this.courseList = courseList; }
|
集合注入部分提取
public class Book { private List<String> list;
public void setList(List<String> list) { this.list = list; } public String toString(){ return "书籍是:"+list+"\t\t"; } } ############################################## <util:list id="booklist"> <value>小王子</value> <value>中王子</value> <value>大王子</value> </util:list> <bean id="book" class="com.miao.collection.Book"> <property name="list" ref="booklist"></property> </bean> ######################################
|
需要改的地方(提取注入部分)
IOC操作bean管理(FactoryBean)
spring有两种类型bean,普通bean,工厂bean(factorybean)
普通bean:在配置文件中定义bean类型就是返回类型
工厂bean:在配置文件中定义bean类型可以和返回类型不一样
- 创建类,实现接口factorybean
- 实现接口里面的方法,在方法中定义返回的bean类型
public class FacBean implements FactoryBean<Course> { @Override public Course getObject() throws Exception { Course course = new Course(); course.setCname("缘起,人群中看见你"); return course; }
@Override public Class<?> getObjectType() { return null; }
@Override public boolean isSingleton() { return FactoryBean.super.isSingleton(); } } ################################################ <!-- 配置FacBean对象--> <bean id="facBean" class="com.miao.factorybean.FacBean"> </bean> ################################################ @Test public void testFacBean(){ ApplicationContext context = new ClassPathXmlApplicationContext("facbean.xml"); Course course=context.getBean("facBean", Course.class); System.out.println(course);
} }
|
IOC操作Bean管理-bean作用域
在spring中,默认情况下,bean是单例对象
设置单实例和多实例
- spring配置文件bean标签里面属性(scope)
- singleton:单实例对象
- prototype:多实例对象
singleton和prototype的区别
- singleton时:加载spring配置文件时就会创建单实例对象
- prototype时:不会在加载spring配置文件时创建对象,在调用getbean方法 时创建多实例对象
IOC操作Bean管理-bean生命周期
生命周期:
bean生命周期
- 通过构造器创建bean实例(无参构造)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 调用bean的初始化方法(需要配置初始化方法)
- bean可以使用了(对象获取了)
- 容器关闭时候,调用bean的销毁方法(配置销毁的方法)
package com.miao.bean;
public class Order { private String oname;
public Order() { System.out.println("第一步,调用无参方法创建对象"); }
public void setOname(String oname) { this.oname = oname; System.out.println("第二步,set方法属性注入"); } public void initMethod(){ System.out.println("第三步,调用bean的初始化方法"); } public void destoryMethod(){ System.out.println("第五步,调用bean的销毁方法"); } } ######################################### <!-- bean 的生命周期--> <bean id="order" class="com.miao.bean.Order" init-method="initMethod" destroy-method="destoryMethod"> <property name="oname" value="bean生命周期"></property> </bean> ############################################# @Test public void testBean1(){ //加载spring配置文件 // ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); //获取配置创建的对象 Order order=context.getBean("order", Order.class); System.out.println("第四步,获取创建bean的实例对象"); System.out.println(order); //主动销毁 context.close(); }
|
bean的后置处理器
- 通过构造器创建bean实例(无参构造)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 把bean实例传递bean后置处理器方法(postProcessBeforeInitialization)
- 调用bean的初始化方法(需要配置初始化方法)
- 把bean实例传递bean后置处理器方法(postProcessAfterInitialization)
- bean可以使用了(对象获取了)
- 容器关闭时候,调用bean的销毁方法(配置销毁的方法)
public class MyBeanPost implements BeanPostProcessor {
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化之前执行");
return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化之后执行"); return bean; } } ############################################## <!-- bean 的生命周期--> <bean id="order" class="com.miao.bean.Order" init-method="initMethod" destroy-method="destoryMethod"> <property name="oname" value="bean生命周期"></property> </bean> <!-- 配置bean后置处理器--> <bean id="myBeanPost" class="com.miao.bean.MyBeanPost"></bean>
|
IOC操作Bean管理(基于注解)
IOC操作Bean管理-xml自动装配
自动装配:
根据装配规则(属性名称或者属性类型),spring自动匹配属性值进行注入
<!--实现自动装配 bean标签属性,实现自动装配 autowire常用俩个值 byName:根据属性名称注入,注入bean的id值和类属性名称一样 byType:根据类型注入
--> <bean id="emp" class="com.miao.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.miao.autowire.Dept"></bean> ################################################ public class Emp { private Dept dept;
public void setDept(Dept dept) { this.dept = dept; }
@Override public String toString() { return "Emp{" + "dept=" + dept + '}'; } public void test(){ System.out.println("自动装配属性"); } } #################################################### public class Dept { } ###################################################### @Test public void testAutowire(){ ApplicationContext context = new ClassPathXmlApplicationContext("autowire.xml"); Emp emp=context.getBean("emp", Emp.class); System.out.println(emp.toString()); emp.test();
}
|
IOC操作Bean管理-引入外部文件
直接配置数据库信息
<!-- 直接配置 数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/school"></property> <property name="name" value="root"></property> <property name="password" value="123456"></property> </bean>
|
引入外部属性文件配置数据源连接池
<!-- 引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClass}"></property> <property name="url" value="${url}"></property> <property name="username" value="${username}"></property> <property name="password" value="${password}"></property> </bean>
|
IOC操作Bean管理-基于注解
spring针对bean管理中==创建对象==提供注解
@component
@service
@controller
@repository
注解功能都是一样的
基于注解创建对象
引入依赖
spring-aop-xx.jar
开启组件扫描
##################################################### <!--开启组件扫描 1.扫描多个包,使用`,`隔开 2.扫描包的上层目录 --> <context:component-scan base-package="com.miao"></context:component-scan>
|
测试一波
@Service(value = "userService") public class UserService { public void add(){ System.out.println("userService add---------------"); } } ################################################ <!--开启组件扫描 1.扫描多个包,使用`,`隔开 2.扫描包的上层目录 --> <context:component-scan base-package="com.miao.annotation"></context:component-scan> ############################################# @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("annotation.xml"); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); }
|
基于注解方式实现属性注入
- @autowired:根据属性类型注入
- @qualifier:根据属性名称注入
- @resource:可以根据名称和类型注入属性
- @value:注入普通类型属性
使用注解的目的:简化xml配置
@autowired–根据属性类型进行注入
public interface UserDao { public void add(); } ###################################### @Repository(value = "laoda") //相当于在bean中创建对象 public class UserDaoImpl implements UserDao{ @Override public void add() { System.out.println("userdao add-----------"); } } ############################################ //value值 相当于id值 <bean id="userService" class=""></bean> //@Service相当于 xx.xml文件中的bean对象 @Service(value = "userService") public class UserService { /* 定义dao类型属性 不需要添加set方法 添加注入 属性注解 */ // @Qualifier("laoda")//根据名称进行注入 @Autowired private UserDao userDao; public void add(){ System.out.println("userService add---------------"); userDao.add(); } }
|
@qualifier–根据名称进行属性注入,需要搭配@autowired 一起使用
@resource:可以根据类型或者名称注入
autowired 和 resource 的小区别
@value
完全注解开发
创建配置类,代替xml配置文件
@Configuration
@ComponentScan(basePackages = {"com.miao.annotation"}) public class SpringConfig { }
|
测试
Aop
aop概念
- 面向切面编程
- 理解:在不通过修改源代码情况下,主干部分添加一个新功能
aop底层原理–两种情况动态代理
有接口情况,使用JDK动态代理
没有接口
jdk动态代理实现
调用newProxyInstance方法
public interface UserDao { int add(int a,int b); String update(String id); } ###############################################
public class UserDaoImpl implements UserDao{ @Override public int add(int a, int b) { System.out.println("add方法执行了---------"); return a+b; }
@Override public String update(String id) { System.out.println("update方法执行了---------"); return id; } } ################################################### package com.miao.newproxy;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays;
public class JDKProxy { public static void main(String[] args) { Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
String update = dao.update("22"); System.out.println(update); } }
class UserDaoProxy implements InvocationHandler{
private Object obj; public UserDaoProxy(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法之前执行。。。。。。。。"+method.getName()+":传递的参数"+ Arrays.toString(args)); Object result = method.invoke(obj, args); System.out.println("方法之后执行。。。。。。。。"+obj); return result; } }
|
结果
AOP术语
连接点
类里面哪些方法可以被增强,这些方法称为连接点
切入点
实际被真正增强的方法,称为切入点
通知(增强)
实际增强的逻辑部分称为通知
通知的类型:
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
切面
把通知应用到切入点的过程
AOP操作
spring框架一般基于aspectj实习AOP操作
- aspectj不是spring组成部分,独立AOP框架,一般aspectj和spring框架一起使用,进行aop操作
基于aspectj实现aop操作
切入点表达式:
基于注解实现
@Component public class User {
public void add(){ System.out.println("add 方法------------"); } } ####################################################
@Component @Aspect public class UserProxy {
@Before(value = "execution(* com.miao.aopannotation.User.add(..))") public void before(){ System.out.println("before执行了"); } } ######################################################## <!--开启组件扫描 1.扫描多个包,使用`,`隔开 2.扫描包的上层目录 --> <context:component-scan base-package="com.miao.aopannotation"></context:component-scan> <!-- 开启aspectj代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> ################################################### @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("aopannotation.xml"); User user = context.getBean("user", User.class); user.add(); }
|
@Component @Aspect public class UserProxy {
@Before(value = "execution(* com.miao.aopannotation.User.add(..))") public void before(){ System.out.println("before执行了"); } @After(value = "execution(* com.miao.aopannotation.User.add(..))") public void after(){ System.out.println("After............."); } @AfterReturning(value = "execution(* com.miao.aopannotation.User.add(..))") public void afterReturning(){ System.out.println("AfterReturning执行了"); } @AfterThrowing(value = "execution(* com.miao.aopannotation.User.add(..))") public void afterThrowing(){ System.out.println("AfterThrowing执行了"); } @Around(value = "execution(* com.miao.aopannotation.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("Around之前执行了");
proceedingJoinPoint.proceed(); System.out.println("Around之后执行了"); } }
|
异常通知
注意点–相同切入点抽取
注意点–多个增强类对同一个方法增强,设置增强类优先级
在增强类上面添加注解@order(数字类型值),数字越小优先级越高
完全注解开发
JdbcTemplate
事务管理