spring5
作者:互联网
Spring5
1.什么是Spring
-
是一个轻量级(jar包少)的开源的JAVAEE框架(容器)
-
是为了解决企业应用开发的复杂性
-
支持事务的处理,对框架整合的支持
-
两个核心部分:IOC和AOP
- IOC:控制反转,把创建对象的过程交给Spring进行管理
- AOP:面向切面,不修改源代码进行功能增强
-
Spring的特点
- 方便解耦,简化开发
- Aop编程支持
- 方便程序测试
- 方便和其他框架进行整合
- 方便进行事务操作
- 降低了API的开发难度
官网下载地址:https://repo1.maven.org/maven2/org/springframework/spring/
Github下载地址: GitHub - spring-projects/spring-framework: Spring Framework
Maven(导Spring web Mvc):
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.13</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.13</version> </dependency>
-
组成
2.IOC理论推导
引入:
-
首先我们的Dao层和service层
-
当我们业务层Service调用Dao层时,会有一个创建Dao实现类的方法,并且有一个get方法去获取
public UserDao userDao=new UserDaoImpl(); //public UserDao userDao=new UserDaoImpl2(); 修改的业务 @Override public void getUser() { System.out.println(userDao.run()); }
-
测试类中
UserService userService = new UserServiceImpl(); userService.getUser();
-
上面的我们就会发现一个弊端,当我们的业务需要修改时,我们必须去修改业务层的代码
-
这时就出来了一种解决办法,我们用一个set方法控制创建哪一种业务的对象
public UserDao userDao; public void setUserDao(UserDao userDao){ this.userDao=userDao; } @Override public void getUser() { System.out.println(userDao.run()); }
-
测试类时,我们可以先调用set方法来选择不同的业务,这就是IOC的原型
@Test public void test(){ UserService userService = new UserServiceImpl(); ((UserServiceImpl)userService).setUserDao(new UserDaoImpl()); userService.getUser(); }
-
我们从主观的去创建对象,变成被动的去接受对象
-
这种思想,从本质上解决了问题,我们程序员不需要去管理对象的创建,程序的耦合性降低,可以更加专注在业务的实现上,这就是IOC的原型
3.IOC本质
- 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了
- IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
- 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
4.HelloSpring
4.1丶实体类
public class Hello {
private String name;
public void setName(String name) { //注意这里set方法必须有(依赖注入 : 就是利用set方法来进行注入的.)
this.name = name;
}
public void show(){
System.out.println(name+"你好呀!");
}
}
4.2丶写bean配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
原来:Hello hello =new Hello();
现在:bean就代表一个对象,id是对象名,class是映射到对象类的位置(使用完全限定的类名)
property 设置属性和属性值,一个属性就要对象相对的set
-->
<bean id="Hello" class="com.LiuDeHen.pojo.Hello">
<property name="name" value="spring"/>
value=""//具体的值
ref=""//使用Spring容器中创建的对象
</bean>
</beans>
4.3丶测试
public void test(){
// 获取Spring上下文对象!
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// getBean获取id=Hello的bean对象
Hello hello = (Hello) context.getBean("Hello");
hello.show();
}
4.4丶总结:
- 上面的过程 就叫控制反转 :
- 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的 .
- 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
- 依赖注入 : 就是利用set方法来进行注入的. (跟上面推导的IOC原型一样)
- IOC是一种编程思想 , 由主动的编程变成被动的接收 .
- 所谓的IOC就是:Spring去创建,管理,装配对象
5.IOC创建的方式
5.1丶默认
- 是使用无参构造创建
5.2丶 有参构造
-
有参怎么创建对象?
-
第一种:使用下标
-
第二种:使用参数类型(当有相同类型就不能使用,不推荐)
-
第三种:使用属性名(推荐)
<!-- 第一种方式 index:表示第几个参数 --> <bean id="Hello" class="com.LiuDeHen.pojo.Hello"> <constructor-arg index="0" value="Spring"/> <constructor-arg index="1" value="5"/> </bean> <!--第二种方式 type:表示构造器的参数类型,可以填多个,但是当有多个相同类型就不能用了,不推荐 --> <bean id="Hello" class="com.LiuDeHen.pojo.Hello"> <constructor-arg type="java.lang.String" value="Spring"/> <constructor-arg type="int" value="5"/> </bean> <!-- 第三种方式 直接通过参数名 --> <bean id="Hello" class="com.LiuDeHen.pojo.Hello"> <constructor-arg name="name" value="spring"/> <constructor-arg name="day" value="5"/> <!-- 当传入的值类型是引用类型,可以用ref --> </bean>
5.3丶注意:
spring容器,再一实例化上下文的时候,里面所有bean对象不管是否调用,全部都会创建
6.Spring配置
6.1丶别名
<alias name="Hello" alias="我是傻逼"/>
6.2丶bean配置
<!--
id:是bean对象的唯一标识符
class:对应类的全限定名:包名+类名
name:别名(所以上面的别名没屌用),并且可以同时设置多个
-->
<bean id="Hello" class="com.LiuDeHen.pojo.Hello" name="我是大傻逼 我是小煞笔,我真是傻逼" >
<constructor-arg name="name" value="spring"/>
<constructor-arg name="day" value="5"/>
<!-- 当传入的值类型是引用类型,可以用ref -->
</bean>
6.3丶import
用在团队开发时,可以将多个bean.xml导入合并成一个
<import resource="bean.xml"/>
<import resource="bean2.xml"/>
<import resource="bean4.xml"/>
7.DI依赖注入
7.1丶构造器注入
前面说过
7.2丶set方法注入
-
依赖注入:set注入
- 依赖:bean对象的创建依赖于spring容器
- 注入:bean对象中的所有属性,由容器来注入
-
实例
-
实体类
private int age; private String name; private Arrecess arrecess; private int[]a; private List<String> l; private Map<String,String> m; private Set<String> s; private String wife; private properties info;
-
bean
<bean id="name" class="com.LiuDeHen.Dao.Student" > <!-- 普通注入 --> <property name="name" value="刘超"/> <!-- bean注入,ref --> <property name="arrecess" ref="arrecess"/> <!-- 数组注入 --> <property name="a"> <array> <value>1</value> <value>2</value> <value>3</value> </array> </property> <!--list注入--> <property name="l"> <list> <value>1</value> <value>2</value> <value>你好</value> <value>true</value> </list> </property> <!-- set注入 --> <property name="s"> <set> <value>1</value> <value>1</value> <value>你好</value> </set> </property> <!-- map注入 --> <property name="m"> <map> <entry key="One" value="1"/> <entry key="2" value="Two"/> <entry key="True" value="False"/> </map> </property> <!--null注入--> <property name="wife"> <null> </property> <!--properties配置文件--> <property name="info"> <props> <prop key="driver">com.mysql.jdbc.driver</prop> <prop key="url">jdbc:mysql://localhost:3306/lc</prop> <prop key="username">root</prop> <prop key="password">123</prop> </props> </property> </bean>
-
测试
public void test(){ ClassPathXmlApplicationContext classEmitterTransformer = new ClassPathXmlApplicationContext("bean.xml"); Student name = (Student)classEmitterTransformer.getBean("name"); System.out.println(name.getName()); // 遍历数组 for (int i : name.getA()) { System.out.println(i); } // 遍历list for (Object o : name.getL()) { System.out.println(o); } // 遍历set for (String s : name.getS()) { System.out.println(s); } // 遍历map HashMap<String, String> m = (HashMap<String, String>) name.getM(); for (String s : m.keySet()) { String value = m.get(s); System.out.println("key:"+s+" value:"+value); } }
-
7.3丶拓展方式注入
-
用的时候先导依赖
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
-
p命名空间:实质就是set注入
<!-- p命名空间,就是property属性的缩写--> <bean id="name" class="com.LiuDeHen.Dao.Student" p:age="20" p:name="lc"/>
-
c命名空间:实质就是构造器注入
<!-- c:命名空间,就是constructor-arg的缩写 -->
<bean id="name" class="com.LiuDeHen.Dao.Student" c:name="lc"/>
7.4丶bean作用域
-
单例模式(默认模式,全局,所有人共享一个对象)
<!-- 单例 --> <bean id="name2" class="com.LiuDeHen.Dao.Student" c:name="lc" scope="singleton"/>
-
原型模式(每一个bean对应一个单独的对象)
<!-- 原型 --> <bean id="name1" class="com.LiuDeHen.Dao.Student" c:name="lc" scope="prototype"/>
-
其他的再web开发中使用
-
测试
Student name1 = (Student)classEmitterTransformer.getBean("name1");
Student name2 = (Student)classEmitterTransformer.getBean("name2");
System.out.println(name1.hashCode());
System.out.println(name2.hashCode());
发现hashcode不同不是同一个对象
8.bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式!
- Spring会在上下文中自动寻找,并自动给bean装配属性
8.1丶在Spring中有三种装配方式
- 在xml中显示的配置
- 在java中显示配置
- 隐式的自动装配bean [重要]
-
准备
private Cat cat; private Dog dog; private String name;
8.2丶byname和byType
- bean
<!--
autowire:会在spring容器上下文自动匹配
autowire=byname:根据自己对象set方法后面的值对应的bean id匹配
autowire="byType:根据class你的对象类型来找相同的bean
-->
<!-- <bean id="Human" class="com.LiuDeHen.Dao.Human" autowire="byName">-->
<bean id="Human" class="com.LiuDeHen.Dao.Human" autowire="byType">
<property name="name" value="lc"/>
</bean>
-
测试
public void test(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml"); Human human = applicationContext.getBean("Human", Human.class); human.getCat().shout(); human.getDog().shout(); }
8.3丶小结
-
byname的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值对应
-
byType的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型的值对应
8.4丶使用注解实现自动装配
使用注解须知:
-
导入约束: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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/>
@Autowired:
直接在对应的属性上使用,也可以在set方法上使用
使用Autowired我们可以不用写set方法了,前提是你这个自动装配的的属性在IOC容器里存在,并且Byname对应
当我们设置required=false,说明这个对象可以为null
public @interface Autowired {
boolean required() default true;
}
注意:
当注入在IoC容器中该类型只有一个时,就通过byType进行装配
当注入容器存在多个同一类型的对象时,就是根据byName进行装配
@Qualifier:
用法: @Qualifier("指向Bean的id")
一般是用来配合@Autowired来使用,指定一个唯一的bean对象注入
1.首先
<!--同一个类型有多个,此时是使用byName来装配 -->
<bean id="dog11" class="com.LiuDeHen.Dao.Dog"/>
<bean id="dog22" class="com.LiuDeHen.Dao.Dog"/>
<bean id="cat11" class="com.LiuDeHen.Dao.Cat"/>
<bean id="cat22" class="com.LiuDeHen.Dao.Cat"/>
2.这个时候实体类
//此时我们发现id与之bean里的id没有匹配的,所以会报错
@Autowired
private Cat cat;
@Autowired
private Dog dog;
3.此时可以使用注解@Qualifier指向指定的Bean下的id
@Autowired
@Qualifier("cat11")
private Cat cat;
@Autowired
@Qualifier("dog22")
private Dog dog;
@Resource:
跟@Autowired和@Qualifier联用差不多效果,但是效率偏低
@Resource
private Cat cat;
@Resource(name="dog2")
private Dog dog;
private String name;
@Nullable:放在字段上,说明这个字段可以为null
9.使用注解开发
在Spring4之后,使用注解开发必须要导入aop的包
导入约束和支持,并需要扫描包
<!--扫描包 -->
<context:component-scan base-package="com.LiuDeHen.pojo"/>
1.bean
@Component:创建bean对象
2.属性如何注入
@value:给属性赋值:相当于
//Component:跟xml里的创建<bean id="user" class="com.LiuDeHen.pojo.User"> 一样的作用
// Component:组件:放在类上,说明这个类呗Spring管理了,就是bean
@Component
public class User {
@Value("nb")
private String name;
3.衍生的注解
@Component有几个衍生的注解,我们在web开发中,会按照MVC三层架构来分层!
Dao:[@Repository]
service:[@Service]
controller:[@Controller]
注意:这几个注解的功能是一样的,都是将类注册到Spring容器中
4.自动装配
上面单独说过
@Autowired:和@Qualifier:
@Resource:
@Nullable:放在字段上,说明这个字段可以为null
5.作用域
@Scope("singleton")
6.小结
注解和xml:
-
注解:创建的bean对象只能自己使用,不能被其他类调用,维护相对困难
-
xml:更加万能,适用于任何场景,维护简单方便
-
最佳实现:xml负责管理bean,注解用来属性注入
10.使用java的方式配置Spring
-
创建实体类
public class User { @Value("六的很") private String name; public String getName() { return name; } }
-
使用一个配置类代替xml文件
-
使用注解@Bean和@Configurable
-
@Configurable:
@Configuration
是一个类级注释,指示对象是 Bean 定义的源 (容器),并且Configurable本身就是里面就有autowirepublic @interface Configurable { String value() default ""; Autowire autowire() default Autowire.NO;
-
Bean:就是之前xml里的一个bean对象
-
id就是方法名
-
class就是方法返回值
-
还有注解@import():将其他配置类合并
@Configurable public class config { @Bean public User getUser(){ return new User(); } }
-
-
测试类
- 跟之前不同的是现在使用的是通过类获取Spring上下文
- 使用类AnnotationConfigApplicationContext
@Test public void test(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(config.class); User getUser = context.getBean("getUser", User.class); String name = getUser.getName(); System.out.println(name); } }
11.阶段总结
1.什么是spring
- spring是一个开源轻量级框架
- 为了简化企业开发
2.spring核心
- **IOC容器**
- **AOP切面编程**
3.IOC容器的推导以及意义
- 原本
- 在业务层创建Dao层的对象
- 每使用一个对象创建一次
- IOC容器的由来
- 在业务层创建一个set方法,参数为Dao的接口,返回一个Dao对象(多态)
- 在我们的测试类中,不同的对象只需要设置set里的Dao对象即可
- 意义:**由主动的创建对象,变成我们可以被动的管理对象**,降低耦合性
- **IOC:控制反转**
4.怎么用spring使用IOC容器
4.1丶IOC是一种容器(思想),DI是注入(手段)
- set注入:
- 首先必须要有这个set方法
- 再在property属性中就可以了
- 构造器注入
- 首先要有相对应的构造器,默认无参
- 使用构造器的标签constructor-arg
- 有使用对应参数名(推荐),参数下标,参数类型多种匹配方式
- bean作用域:
- 属性:scope
- 有单例,所有对象共用:singleton
- 原型:单对象独享:prototype
4.2丶使用xml的方式创建
- 创建实体类
- 创建bean.xml文件,导入spring容器配置
- 设置xml文件中的bean,id为唯一标识,class为类的路径,一个bean为一个对象
- bean中标签property为属性
- 基础类型:name为属性名,value为值
- 其他类型,list就是又list标签,array就是array标签等
- 测试类创建spring容器上下文对象 new ClassPathXmlApplicationContext("xml文件")
4.3丶自动装配(隐式创建):
- xml和使用java都是显示创建
- 常用有:byName,ByType
- autowire=byname:根据id值来自动装配
- autowire="byType:根据class你的类型来装配
4.4丶使用注解创建
- 在xml文件中
```xml
<!--扫描包 -->
<context:component-scan base-package="com.LiuDeHen"/>
其他的bean都
```
- 在对应类上使用注解**@Component**,就可以**创建bean**对象
- 使用@value:给属性赋值
- 自动装配@Autowired
4.5丶使用全java的方式(在springboot很常用)
- 创建一个实体类
- 创建一个配置类,有一个get方法,返回的就是实体类的对象
- get方法上有一个注解**@Bean**,**创建**一个bean对象,类上有一个注解**@Configurable**实现自动装配
- 这个类就是之前的xml文件,每一个get方法就是一个xml里的bean对象,方法名是id,返回值是class
12.代理模式
什么是代理模式?
- 实际的例子:我们在登录,注册的时候,验证码是手机短信,不是我们发送,而是移动,电信等公司面向社会提供发送短信的功能
- 开发中的例子有a,b(代理类),c(目标类)类,a类不能直接(或者不适合)调用c类,但是a类能调用b类,b类能调用c类
为什么要学代理模式?
- AOP底层就是代理模式
- 功能增强:在原有的功能上,新增功能
- 控制访问:代理类不让你访问目标
代理模式的分类
- 静态代理
- 动态代理
12.1丶静态代理
角色分析
- 抽象角色:一般使用接口和抽象类,在这个实例里就是一个出租房接口
- 真实角色:被代理的角色,这里是房东
- 代理角色:代理真实角色,代理角色后,会有一些其他操作,这里是中介
- 客户:访问代理角色的人,这里是客户
抽象角色:
//买卖房接口
public interface Rent {
void rent();
}
真实角色:
//房东类
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东卖房");
}
}
代理角色:
//代理类
public class proxy implements Rent{
private Host H;
public proxy(Host host){
H=host;
}
//继承的父类方法
@Override
public void rent() {
H.rent();
}
//自己的方法
public void sou(){
System.out.println("收取中介费");
}
}
客户:
//客户类
public class client{
public static void main(String[] args) {
proxy proxy = new proxy(new Host());
proxy.rent();
}
}
代理模式的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共也就交给了代理角色,实现了业务的分工
- 公共业务发生拓展的时候,方便集中管理且不修改原来的代码
缺点:
- 一个真实角色就会产生一个代理角色,代码量翻倍,效率变低
12.2丶加深理解
AOP:面向切面编程,横向开发,再不修改代码的情况下,增加业务
12.3丶动态代理
- 动态代理角色和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:----JDK动态代理(我们在这里使用,反射)
- 什么是动态代理?
- 使用jdk的反射机制,创建对象的能力,创建的是代理类的对象
- 动态:在程序执行的过程中,调用jdk提供的方法才能创建代理类的对象
- 使用jdk反射包中的三个类和接口实现动态代理的功能
- 反射包java.lang.reflect三个类:InvocationHandler,Method,Proxy
- InvocationHandler接口就实现一个方法:invoke(),代理类实现的功能就写在里面
- Method类:Method.invoke()执行目标方法
- Proxy类:核心对象,创建代理对象
- 静态方法:newProxyInstance()创建对象
- 什么是动态代理?
- 基于类:cglib
- java字节码实现:javasist
- 基于接口:----JDK动态代理(我们在这里使用,反射)
实现动态代理的步骤
- 创建接口,定义目标类要完成的功能
- 创建目标类
- 创建InvocationHandler接口的实现类,在Invoke()方法中代理类的功能,并返回代理类
- 调用目标方法
- 增强功能
- 使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型
卖房接口类
public interface Rent {
public void rent();
}
房东类
public class Host implements Rent{
@Override
public void rent() {
System.out.println("我是房东我要卖房");
}
}
代理类(动态代理就是控制这里的res,会根据传入的接口和参数返回是哪一个类,从而实现动态)
//1.实现接口InvocationHandler,重写invoke方法实现代理类要做的功能
public class proxy implements InvocationHandler {
//2.创建目标类实现的接口
private Rent rent;
proxy(Rent rent){
this.rent=rent;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res=null;
// 三个参数,proxy:代理类,method:代理类实现的方法,args:参数
res=method.invoke(rent,args);
// 3.可以增加一些额外方法
if (res!=null){
}
// 返回这个类
return res;
}
}
客户类
public class client{
public static void main(String[] args) {
// 1.创建目标对象
Rent r = new Host();
// 2.自己写的实现InvocationHandle接口的类
InvocationHandler handler = new proxy(r);
// 3.创建代理对象,并转成接口
Rent o = (Rent)Proxy.newProxyInstance(r.getClass().getClassLoader(),
r.getClass().getInterfaces(), handler);
// 4.通过代理执行方法
o.rent();
}
好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共也就交给了代理角色,实现了业务的分工
- 公共业务发生拓展的时候,方便集中管理且不修改原来的代码
- 一个接口代表的是一类业务,修改功能只需要修改极少代码
13.AOP
13.1丶基础概念:
-
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等....
-
切面(ASPECT)︰横切关注点被模块化的特殊对象。即,它是一个类。
-
通知(Advice) :切面必须要完成的工作。即,它是类中的一子个方法。
-
目标(Target)︰被通知对象。
-
代理(Proxy)︰向目标对象应用通知之后创建的对象。
-
切入点(PointCut) ︰切面通知执行的“地点"的定义。
-
连接点(JointPoint) :与切入点匹配的执行点。
13.2丶使用Spring的方式实现Aop
导包:aop织入
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
方式一:使用Spring原生API接口
导入约束时一般要导这几种,下面两个就修改最后那一点,比如beans改为aop
-
首先有一个切点类
-
再需要额外类,前面切入
-
导入aop约束
-
注册bean对象
-
使用aop标签advisor实现切入
<bean id="UserService" class="com.LiuDeHen.service.userServiceImpl"/> <bean id="After" class="com.LiuDeHen.Log.afterLog"/> <bean id="Before" class="com.LiuDeHen.Log.beforeLog"/> <!-- 配置aop:导入aop的约束 方式一:使用原生的SpringAPI接口 --> <aop:config> <!-- 切入点:我们在哪个地方执行 execution 要执行的位置! (*(修饰词) *(返回值) *(类名) *(方法名) *(参数)):对应创建一个方法 *:任意字符 ..:(..)两个点代表可以有任意个参数 --> <aop:pointcut id="pointcut" expression="execution(* com.LiuDeHen.service.userServiceImpl.*(..))"/> <!-- 环绕添加 --> <aop:advisor advice-ref="Before" pointcut-ref="pointcut"/> <aop:advisor advice-ref="After" pointcut-ref="pointcut"/> </aop:config>
方式二:自定义类实现
- 一个切入点类
- 一个额外类,使用原生就是一个额外方法一个类,然后注册,自定义就是所有额外方法一个类
- 注册bean
- 使用aop标签,exection表达式
- execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。
<bean id="diy" class="com.LiuDeHen.diy.divPointcut"/>
<aop:config>
<!-- 自定义切面 ref:要引入的类 -->
<aop:aspect ref="diy">
<!-- 切入点 -->
<aop:pointcut id="point" expression="execution(* com.LiuDeHen.service.userServiceImpl.*(..))"/>
<!-- 通知-->
<aop:after method="After" pointcut-ref="point"/>
<aop:before method="Before" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
方式三:使用注解实现AOP
无非就是
- 设置切入面@Aspect
- 设置需要切入的方法是前是后还是环绕@After,@Before,@Around
- 设置切入点(用exection表达式):execution(* com.LiuDeHen.service.userServiceImpl.*(..))
//注册bean(使用前,需要bean里必须有扫描包)
@Component
//开启注解支持,有参数设置为false就是默认为jdk代理,ture为cglie代理
@EnableAspectJAutoProxy
//设置切入面
@Aspect
public class divPointcut {
// 设置切入位置和execution表达式(切入点的位置)
@After("execution(* com.LiuDeHen.service.userServiceImpl.*(..))")
public void After(){
System.out.println("方法执行前");
}
@Before("execution(* com.LiuDeHen.service.userServiceImpl.*(..))")
public void Before(){
System.out.println("方法执行后 ");
}
// 在环绕增强中,给定一个参数ProceedingJoinPoint,表示我们要获取处理切入的点
@Around("execution(* com.LiuDeHen.service.userServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed();
System.out.println("环绕后");
}
}
14丶整合Mybatis
-
导入jar包
- junit
- mybatis
- mysql
- spring
- aop织入
- mybatis-spring
-
配置环境
-
导入spring配置
-
Datesource代替mybatis的数据源,需要类org.springframework.jdbc.datasource.DriverManagerDataSource
-
SqlSessionFactory获取工厂,并可以设置mybatis里的配置(mapper位置等)需要类org.mybatis.spring.SqlSessionFactoryBean
-
SqlSessionTemplate相当于获取了SqlSession,需要类org.mybatis.spring.SqlSessionTemplate
-
Dao接口多了实现类
<!-- 2.Datesource:使用spring的数据源替换mybatis的配置 这里我们使用spring提供的org.springframework.jdbc.datasource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybaties?useSSL=false&;characterEncoding=UTF-8&;useUnicode=true&;serverTimezone=GMT"/> <property name="username" value="root"/> <property name="password" value="123"/> </bean> <!--3.SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 配置的位置 --> <property name="configLocation" value="classpath:mybatisSpring.xml"/> <!-- Mapper的位置 --> <property name="mapperLocations" value="classpath:com/LiuDeHen/Dao/UserMapper.xml"/> </bean> <!-- 4.SqlSessionTemplate:就是我们使用的Sqlsession --> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--只能使用构造器注入SqlSessionTemplate,因为它没有set方法--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <!-- 5.实现类 --> <bean id="UserMapperImpl" class="com.LiuDeHen.Dao.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean>
实现类:第一种方式SqlSessionTemplate public class UserMapperImpl implements UserMapper{ private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } @Override public List<User> select() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.select(); } } 第二种方式:SqlSessionDaoSupport 继承SqlSessionDaoSupport,获取SqlSessionTemplate,并且此时bean里5的实现类属性变成sqlSessionFactory public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{ @Override public List<User> select() { UserMapperImpl mapper = getSqlSession().getMapper(UserMapperImpl.class); return mapper.select(); } }
-
-
测试
-
直接获取实现类的bean对象
@Test public void test(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml"); UserMapperImpl userMapperImpl = applicationContext.getBean("UserMapperImpl", UserMapperImpl.class); for (User user : userMapperImpl.select()) { System.out.println(user); }
-
15.声明式事务
1.回顾事务
-
dml业务要么都成功,要么都失败
-
确保完整性和一致性
事务的ACID原则(原一隔持):
- 原子性:确保dml业务,要么都成功,要么都失败
- 一致性:一旦事务完成,要么都提交,要么失败,资源和状态一直保持一致
- 隔离性:多个事务操作一个数据,防止数据损坏
- 持久性: 事务一旦提交,无论系统发生什么问题,结果都不会受到影响,被持久化写到硬盘
2.使用声明创建事务
-
配置声明事务
<!--配置声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dataSource" /> </bean>
-
配置事务的通知
<!--结合AOP实现事务的织入--> <!-- 配置事务的通知--> <tx:advice id="interceptor" transaction-manager="transactionManager"> <!-- 为哪一个方法创建事务 --> <!-- 配置事务的传播特性: propagation=使用 REQUIRED创建,一共有7种 --> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
-
配置事务的切入
<!-- 配置事务的切入 --> <aop:config > <!-- 设置切入点--> <aop:pointcut id="pointcut" expression="execution(* com.LiuDeHen.Dao.UserMapperImpl.*(..))"/> <aop:advisor advice-ref="interceptor" pointcut-ref="pointcut"/> </aop:config>
-
实体类中实现多组dml操作
@Override public int delete(User user) { UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.add(user); mapper.select(); return mapper.delete(user); }
-
当Mapper中的dml操作出现问题
<select id="select" resultType="User"> select * from mybaties.user </select> <insert id="add" parameterType="User"> insert into mybaties.user values (#{id},#{name},#{pwd}); </insert> <delete id="delete" parameterType="User"> 这个语句delete加了s,造成错误 deletes from mybaties.user where id=#{id} </delete>
-
测试就会失败,全部失败,而不是部分失败,没有问题则会全部成功
16.总结
-
什么是spring
- 是一个整合了很多技术,核心点为控制反转(IOC)和面向切面编程(AOP)的轻量级框架
-
spring核心
- IOC
- 什么是IOC?
- IOC为控制反转,是一种思想,由主动的创建对象,到被动管理对象,创建等操作交给spring容器来实现
- 基础实现:
- 1.当我们数据操作层Dao的接口有多个方法,不同的实现类继承这个接口
- 2.那么在我们测试的时候,每测试一个实现类,都需要去实例化,主动权在我们程序员手里,那么怎么实现IOC呢
- 3.添加一个业务层Service,实现接口和实体类,并在实体类中,去set和get一个Dao层的接口
- 4.此时我们测试,只需要new业务层,去调用set来实现Dao层哪一个具体的实现类的方法
- 5.好处:此时主动权在用户手上,这就是控制反转
- AOP
- 什么是AOP?
- 面向切面编程,底层是动态代理
- 什么是代理?
- 1.首先有一共目标类,客户类,客户类不能直接调用或者不适用目标类,此时就需要一共代理类
- 2.实例:租客,通过中介找房,中介找房东
- 3.好处:中介可以使用额外的方法,并且不影响到房东和租客(代理类能够在不改变目标类和客户类的情况下,能够添加方法,控制访问)
- 4.动态代理是AOP的底层
- 代理分类
- 静态代理
- 动态代理
- 默认JDK代理必须通过接口实现
- IOC
-
spring怎么用(IOC)
- 第一种方式:bean创建
- 先创建实体类
- 构建bean.xml文件,创建bean对象
- 测试调用这个对象
- 第二种方式:bean扫描,在java类中创建
- 实体类
- bean里扫描包
- 实体类上实现Component创建beans,就是一共对象,然后还可以用value注入值,Autowire自动匹配
- 第三种:纯java创建
- 实体类
- 然后容器类实现注解confige(容器)和bean(对象)
- 测试
- 第一种方式:bean创建
-
springAOP的使用
- 基础概念
- 切面
- 切入点
- 切入位置
- 具体使用:
- 第一种方式:原生springAPI的使用
- 导依赖aop的织入,和aop的约束
- 创建aop标签,设置切面,切点
- 第二种方式:
- 第三种方式:
- 第一种方式:原生springAPI的使用
- 基础概念
-
spring-mybatis的连用
标签:对象,创建,代理,private,bean,public,spring5 来源: https://www.cnblogs.com/LiuDeHen/p/15956533.html