Spring
IOC原理
-
控制反转,把创建对象和对象之间的调用过程交给spring处理
-
目的:降低耦合度
-
案例
-
beans.xnl
<?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="cn.mucd.entity.User"/> </beans>
-
User.java
-
public class User { public void add(){ System.out.println("add init ...."); } }
-
测试
-
@Test public void test01() { //读取配置文件 ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) classPathXmlApplicationContext.getBean("user"); user.add(); }
-
输出
add init ....
-
-
IOC底层使用到了 xml 解析、工厂模式、反射
BeanFactory接口
- IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
- IOC容器实现的两种方式
BeanFactory
:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用 * 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象ApplicationContext
:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人 员进行使用
- ApplicatoinContext接口有实现类[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S8QfhBZJ-1647920780409)(C:\Users\mucd\AppData\Roaming\Typora\typora-user-images\1647910899933.png)]
IOC操作Bean管理
-
Bean管理是指两个操作
-
spring创建对象
-
spring注入属性
-
操作的两种方式
-
基于xml实现
-
<bean id="user" class="cn.cn.mucd.entity.User"></bean>
-
在bean标签里添加对应的属性,就能实现对象穿件
-
id属性: 唯一标识
-
class属性: 类路径,包括包名
-
-
基于xml注入属性
-
DI: 依赖注入,就是注入属性
-
使用set方法进行注入
-
public class Book { //创建属性 private String bookName; private String email; //创建set方法 public void setBookName(String bookName) { this.bookName = bookName; } public void setEmail(String email) { this.email = email; } }
-
<!--set 方法进行属性注入--> <bean id="book" class="cn.mucd.entity.Book"> <property name="bookName" value="爱情故事"/> <property name="email" value="213123@qq.com"/> </bean>
-
-
使用有参构造进行注入
-
创建类,定义属性,创建属性对应有参数构造方法
-
public class Book { private String bookName; private String email; public Book() { } public Book(String bookName, String email) { this.bookName = bookName; this.email = email; } }
-
<bean id="book" class="cn.mucd.entity.Book"> <constructor-arg name="bookName" value="隔山打牛"/> <constructor-arg name="email" value="12312@qq.com"/> </bean>
-
-
注入外部Bean
-
创建类service 类和 dao 类
-
//service public class UserService{ //创建 UserDao 类型属性,生成 set 方法 private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void add() { System.out.println("service add..............."); userDao.update(); } } //dao接口和实现 public interface UserDao { int update(); } public class UserDaoImpl implements UserDao{ @Override public int update() { System.out.println(" dao update .... "); return 1; } }
-
-
在 service 调用 dao 里面的方法
-
在 spring 配置文件中进行配置
-
<bean id="userDao" class="cn.mucd.dao.UserDaoImpl"/> <bean id="userService" class="cn.mucd.servicew.UserService"> <property name="userDao" ref="userDao"/> </bean>
-
运行测试
-
@Test public void test02(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); }
-
-
注入属性,内部bean
-
创建类
-
//部门 public class Dept { private String dname; public void setDname(String dname) { this.dname = dname; } } //员工 public class Emp { private String ename; private Dept dept; public void setEname(String ename) { this.ename = ename; } public void setDept(Dept dept) { this.dept = dept; } }
-
<!--注入 内部bean--> <bean id="emp" class="cn.mucd.entity.Emp"> <property name="ename" value="女员工"/> <!--设置内部属性--> <property name="dept"> <bean class="cn.mucd.entity.Dept"> <property name="dname" value="人事部"/> </bean> </property> </bean>
-
运行
-
@Test public void test03(){ ApplicationContext text = new ClassPathXmlApplicationContext("beans.xml"); Emp emp = (Emp) text.getBean("emp"); System.out.println("emp = " + emp); }
-
-
-
级联赋值
-
<!--注入属性 级联赋值--> <bean id="emp2" class="cn.mucd.entity.Emp"> <property name="dept" ref="dept2"/> <property name="ename" value="anan"/> </bean> <bean id="dept2" class="cn.mucd.entity.Dept"> <property name="dname" value="美女部门"/> </bean>
-
-
集合注入
-
@ToString public class Coll { private List<String> list; private Set<String> set; private Map<String, Object> map; private String[] strs; public void setList(List<String> list) { this.list = list; } public void setSet(Set<String> set) { this.set = set; } public void setMap(Map<String, Object> map) { this.map = map; } public void setStrs(String[] strs) { this.strs = strs; } }
-
<!--注入集合属性--> <bean class="cn.mucd.entity.Coll" id="coll"> <property name="strs"> <array> <value>arr1</value> <value>arr2</value> <value>arr3</value> </array> </property> <property name="list"> <list> <value>list1</value> <value>list2</value> <value>list3</value> </list> </property> <property name="set"> <set> <value>set1</value> <value>set2</value> <value>set3</value> </set> </property> <property name="map"> <map> <entry key="name" value="zangsan"/> <entry key="addr" value="bj"/> </map> </property> </bean>
-
-
-
IOC操作bean管理 FactoryBean
-
Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
-
普通 bean:在配置文件中定义 bean 类型就是返回类型
-
工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
- 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
- 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
-
代码实现
-
public class MyBean implements FactoryBean<Course> { //定义返回 bean @Override public Course getObject() throws Exception { Course course = new Course(); course.setCname("abc"); return course; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }
-
<bean id="myBean" class="com.spring5.factorybean.MyBean"> </bean>
-
@Test public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Course course = context.getBean("myBean", Course.class); System.out.println(course); }
-
-
bean的作用域
-
spring的bean默认是单例对象
-
设置bean标签的
scope
属性改变作用域-
默认值,singleton,表示是单实例对象
-
prototype表示多例对象
-
<bean id="user" class"com.spring5.factorybean.user" scope="prototype"/>
-
-
-
bean的生命周期
-
生命周期: 从创建到销毁的过程
-
周期
-
通过构造器创建bean的实例(无参构造)
-
bean的属性设置值和对其他bean引用(调用set )
-
调用bean的初始化方法
-
使用bean(已经获取到的对象)
-
public class Orders { //无参数构造 public Orders() { System.out.println("第一步 执行无参数构造创建 bean 实例"); } private String oname; public void setOname(String oname) { this.oname = oname; System.out.println("第二步 调用 set 方法设置属性值"); } //创建执行的初始化的方法 public void initMethod() { System.out.println("第三步 执行初始化的方法"); } //创建执行的销毁的方法 public void destroyMethod() { System.out.println("第五步 执行销毁的方法"); } } ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Orders orders = context.getBean("orders", Orders.class); System.out.println("第四步 获取创建 bean 实例对象"); System.out.println(orders); //手动让 bean 实例销毁 context.close();
-
bean后置处理器
- bean 的后置处理器,bean 生命周期有七步
- 通过构造器创建 bean 实例(无参数构造)
- 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
- 把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
- 调用 bean 的初始化的方法(需要进行配置初始化的方法)
- 把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
- bean 可以使用了(对象获取到了)
- 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
-
-
创建类,实现接口 BeanPostProcessor,创建后置处理器
-
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 id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
-
-
xml自动装配
-
根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
-
<!--实现自动装配 bean 标签属性 autowire,配置自动装配 autowire 属性常用两个值: byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样 byType 根据属性类型注入 --> <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName"> <!--<property name="dept" ref="dept"></property>--> </bean> <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
-
-
外部属性配置文件
-
<!--直接配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean>
-
-
引入外部文件
-
<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" xmlns:util="http://www.springframework.org/schema/util" 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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="url" value="${prop.url}"></property> <property name="username" value="${prop.userName}"></property> <property name="password" value="${prop.password}"></property> </bean>
-
-
-
基于注解实现
-
简化xml配置
-
使用在类上,方法上,属性上
-
针对创建对象提供注解
- @Component
- @Service
- @Controller
- @Repository
- 以上功能一样, 都可以用来创建 bean 实例
-
实现对象创建
-
引入aop依赖
-
开启组件扫描
-
<context:annotation-config />
-
进行注解驱动注册,从而使注解生效
-
用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
-
如果不扫描包,就需要手动配置bean
-
如果不加注解驱动,则注入的值为null!
-
<!--开启组件扫描 1 如果扫描多个包,多个包使用逗号隔开 2 扫描包上层目录 --> <context:component-scan base-package="cn.spring"></context:component-scan> <context:annotation-config />
-
-
-
-
-
创建类,在类上添加注解
```java //如果不写值,默认就是把类名首字母小写的驼峰命名,如Book->book , UserInfo->userInfo @Component("person") public class Person { public void addPerson(){ System.out.println("add person ...."); } } @Test public void test06(){ ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); //这里填写@Component里的值就可以 Person person = (Person) app.getBean("person"); person.addPerson(); } ``` 5. 作用域注解 `@Scope` 1. singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。 2. prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收 3. ```java @Component("user") @Scope("prototype") public class User{} ```
-
基于Java类进行配置
-
JavaConfig原本是spring的子项目,通过Java类的方式提供Bean的定义信息,在Spring4版本JavaConfig已经正式成为Spring的核心功能
-
//创建SpringConfig.java @Configuration("springAnno") public class SpringAnno { @Bean public Pet pet(){ return new Pet(); } } //创建Pet.java @ToString public class Pet { //给属性赋值 @Value("小猫") private String pname; //给方法赋值 @Value("小狗") public void setPname(String pname) { this.pname = pname; } } //测试运行 @Test public void test07(){ //这里要newAnnotationConfigApplicationContext,不要再写new ClassPathXmlApplicationContext了 ApplicationContext context = new AnnotationConfigApplicationContext(SpringAnno.class); Pet pet = (Pet) context.getBean("pet"); System.out.println("pet = " + pet);//pet = Pet(pname=小狗) }
-
这里Pet.java里写了两个@Value,运行的时候输出的是方法的@Value()
-
导入其他配置类
-
使用
@Import()
,这里就类似include
标签导入 -
@Configuration("springAnno") @Import(SpringCnfig.class) public class SpringAnno { @Bean public Pet pet(){ return new Pet(); } }
-
-
关于Java类的配置方式以后会在SpringBoot中大量的用到.
-
AOP
-
什么是
AOP
?- AOP(As[ect Oriented Programming) 面向切面编程
- 通过预编译和运行时动态代理实现程序功能的统一维护的一种技术
-
在Spring中的作用
- 提供声明是事务,允许用户自定义切面
-
重点:
- 横切关注点:
- 跨越应用程序多个模块的方法或功能. 与我们的业务逻辑无关,但是需要关注横切. 如日志,安全,缓存,事务等…
- 切面(ASPECT):
- 横切关注点,被模块化的特殊对象. 即他是一个类
- 通知(Advice):
- 切面必须要完成的工作
- 目标(Target):
- 被通知对象
- 代理(Proxy):
- 向目标对象应用通知之后创建的对象
- 切入点(PointCut):
- 切面通知执行的"地点"的定义
- 连接点(JointPoint):
- 与切入点匹配的执行点
- 横切关注点:
-
5种类型的通知(Advice):
- Aop可以在不改变原有代码的情况下,去增加新的功能.
-
实现AOP
-
使用AOP前,还需要导一个依赖
-
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
-
第一种实现方式
-
//创建接口和实现类 public interface UserService { void add(); void del(); void update(); void findAll(); } //实现类 public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("add user ..."); } @Override public void del() { System.out.println("del user ..."); } @Override public void update() { System.out.println("upd user ..."); } @Override public void findAll() { System.out.println("find user ..."); } }
-
创建增强类,一个前置增强一个后置增强
-
//前置增强类 public class BeforeLog implements MethodBeforeAdvice { /** * @param method 要执行的目标对象的方法 * @param args 被调用的方法参数 * @param target 目标对象 * @throws Throwable 异常 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("前置方法==============="); System.out.println("methodName = " + method.getName()); System.out.println(Arrays.toString(args)); System.out.println("className = " + target.getClass().getName()); } } //后置增强类 public class AfterLog implements AfterReturningAdvice { //returnValue 返回值 //method被调用的方法 //args 被调用的方法的对象的参数 //target 被调用的目标对象 @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了" + target.getClass().getName() +"的"+method.getName()+"方法," +"返回值:"+returnValue); } }
-
最后去application.xml注册实现aop
-
<?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="cn.mucd.aop.advice.AfterLog" id="afterLog"/> <bean class="cn.mucd.aop.advice.BeforeLog" id="beforeLog"/> <bean class="cn.mucd.aop.service.UserServiceImpl" id="userService"/> <!--aop 配置--> <aop:config> <!--expresssion表达式匹配要执行的方法--> <aop:pointcut id="pointcut" expression="execution(* cn.mucd.aop.service.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config> </beans>
-
<!--execution(返回值 类.方法(方法参数)) *代表所有-->
-
运行
-
@Test public void test01() { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); UserService userService = (UserService) context.getBean("userService"); userService.findAll(); } //输出 前置方法=============== methodName = findAll [] className = cn.mucd.aop.service.UserServiceImpl find user ... 后置方法================= methodName = findAll [] className = cn.mucd.aop.service.UserServiceImpl
-
-
aop就是将公共的业务(安全,日志等)和领域业务结合起来,当执行领域业务时将公共业务也加进来,实现公共业务重复利用!本质还是动态代理.
-
第二种实现方式
-
自定义类来实现aop
-
写一个自己的切入类
-
public class MyPointCut { public void before(){ System.out.println("---------方法执行前---------"); } public void after(){ System.out.println("---------方法执行后---------"); } }
-
xml配置
-
<bean class="cn.mucd.aop.service.UserServiceImpl" id="userService"/> <bean class="cn.mucd.aop.pointcut.MyPointCut" id="myPointCut"/> <aop:config> <aop:aspect ref="myPointCut"> <aop:pointcut id="cut" expression="execution(* cn.mucd.aop.service.UserServiceImpl.*(..))"/> <!--自己类里面的方法 before and after--> <aop:before method="before" pointcut-ref="cut"/> <aop:before method="after" pointcut-ref="cut"/> </aop:aspect> </aop:config>
-
运行
-
@Test public void test02() { ApplicationContext context = new ClassPathXmlApplicationContext("mypointcut.xml"); UserService userService = (UserService) context.getBean("userService"); userService.findAll(); }
-
-
第三种方式
-
使用注解实现aop
-
编写一个注解实现的增强类
-
@Aspect public class AnnoPointcut { @Before("execution(* cn.mucd.aop.service.UserServiceImpl.*(..))") public void before(){ System.out.println("anno 前置"); } @After("execution(* cn.mucd.aop.service.UserServiceImpl.*(..))") public void after(){ System.out.println("anno 后置"); } @SneakyThrows @Around("execution(* cn.mucd.aop.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint pj){ System.out.println("环绕前-------"); System.out.println("签名 = " + pj.getSignature());; //执行目标方法 Object proceed = pj.proceed(); System.out.println("环绕后-------"); System.out.println("proceed = " + proceed); } }
-
配置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 http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean class="cn.mucd.aop.pointcut.AnnoPointcut" id="pointcut"/> <bean class="cn.mucd.aop.service.UserServiceImpl" id="service"/> <aop:aspectj-autoproxy/> </beans>
-
运行
-
@Test public void test03() { ApplicationContext context = new ClassPathXmlApplicationContext("anno.xml"); UserService userService = (UserService) context.getBean("service"); userService.findAll(); } //结果 环绕前------- 签名 = void cn.mucd.aop.service.UserService.findAll() anno 前置 find user ... anno 后置 环绕后------- proceed = null
-
持续更新中 …
-