赞
踩
Spring官方中文文档:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/
1.1 spring的maven地址
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.22</version>
</dependency>
<!--下面这个包是用来和mybatis整合-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.22</version>
</dependency>
maven仓库地址:https://mvnrepository.com/
让对象可以动态的变化,不写死。
通过一个set方法去给接口赋值
第一步:maven项目导入jar包
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- spring项目第一步导包 --> <!--导入webmvc的包,可以自动的将一些其他spring包导入--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.22</version> </dependency> <!--下面这个包是用来和mybatis整合--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.22</version> </dependency> </dependencies>
第二步;创建xml文件(用来实例化对象)(对象==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"> <!--上面部分不变--> <!-- 使用Spring来创建对象,在spring这些都称为Bean java中 类型 变量名 = new 类型(); Hello hello = new Hello(); spring中 id = 变量名 class = new 的对象 property相当于给对象中的属性设置一个值! --> <bean id="userbean" class="pojo.User"/> <bean id="hello" class="pojo.HelloSpring">//创建对象并实例化 <property name="name" value="Spring"/>//给对象属性赋值 <!-- 如果属性字段是复合型(对象)则不用value,用ref=“另一个对象的bean ID” --> <!--ref:引用spring容器(这个xml文件)中创建好的对象 value: 基本数据类型的值 --> <property name="user" ref="userbean"/> </bean> </beans>
第三步:测试(运行)
//获取Spring的上下文对象
//这句话是固定的,可变的是变量名和参数名,参数名就是需要的(容器)xml文件,可以传多个
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中管理,我们要使用,直接去里面取出来就可以
Hello hello = (Hello)applicationContext.getBean("hello");
//getBean(String str):这个方法是在beans.xml中取对象,参数为对象的id
思考:
控制: 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring 后 , 对象是由Spring来创建的
反转:程序本身不创建对象 , 而变成被动的接收对象
**1,spring核心:get/set中的set方法,没有set方法无法注入 **
2,正常创建对象是使用的无参构造方法创建对象
<bean id="userbean" class="pojo.User"/>
<!--如果类没有无参构造方法,则无法创建对象和实例化(会报错)-->
3,使用有参构造方法创建对象的方式:
<!--方式一:下标赋值-->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg index="0" value="caishan"/>
<!--index:有参构造方法中,参数的索引位置 value:给这个参数赋的值-->
</bean>
<!--方式二:类型赋值 不建议使用(因为如果多个参数类型一致,则赋值会出错) -->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg type="java.lang.String" value="caishan"/>
<!--根据有参构造方法的参数类型去赋值,String类的type是java.lang.String,其他就正常 (类这些除外)-->
</bean>
<!--方式三:直接参数名赋值 和property一样的用法,引用对象用ref。只是改了标签名-->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg name="name" value="caishan"/>
</bean>
总结:
1,spring创建对象,是在配置文件中bean时就被初始化。
2,如果有有参构造方法,则属性通过property标签进行赋值即可。如果没有有参构造方法(代码中只有有参构造方法)贼需要通过constructor-arg标签对属性进行赋值。
5.1 alias标签(别名)
<!--通过别名获取对象,id叫user的bean 可以用abc来代替-->
<alias name="user" alias="abc"/>
5.2 Bean标签的配置
<!--
id: bean的唯一标识,对象名
class: bean对象所对应的全限类名: 包名+类名
name: 也是别名,而且name同时可以取多个别名,中间用空格,逗号分开都可以(比alias更高级)
-->
<bean id="user" class="com.kuang.pojo.User" name="ab abc">
<constructor-arg name="name" value="ppj"/>
</bean>
5.3 import标签
一般用于团队开发,可以将多个配置文件,导入合并为一个
多人开发,不同的类需要注册到不同的bean中,可以利用import将所有的beans.xml合并
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
//导入了三个beans.xml容器
//使用时直接利用总的xml文件,就可以使用全部的
</beans>
要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is 。。。。
<?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"> <!--上面部分不变--> <bean id="adderss" class="pojo.Address"> <property name="address" value="重庆"/> </bean> <!----> <bean id="Student01" class="pojo.Student"> <!--普通数据类型,直接使用value注入--> <property name="name" value="蔡闪"/> <!--其他类数据类型,用ref注入--> <property name="address" ref="adderss"/> <!--数组类型,在property标签体内使用array标签注入--> <property name="books"> <array> <value>aaa</value> <value>bbb</value> <value>ccc</value> </array> </property> <!--list集合类型,在property标签体内使用list标签注入--> <property name="hobbys"> <list> <value>111</value> <value>222</value> <value>333</value> </list> </property> <!--map集合类型,在property标签体内使用map标签注入--> <property name="card"> <map> <entry key="ID" value="11223344"/> </map> </property> <!--set集合类型,在property标签体内使用set标签注入--> <property name="games"> <set> <value>qqqq</value> </set> </property> <!--null类型,在property标签体内使用null标签注入--> <property name="wife"> <null/> </property> <!--Properties类型,在property标签体内使用props标签注入(有点像结构体)--> <property name="info"> <props> <prop key="姓名">111</prop> <prop key="性别">男</prop> </props> </property> </bean> </beans>
几个注意点:
1,如果数据类型是值,则用value 。如果是对象之类的用ref
2,不变的是 这个部分,基本上都可以放在标签体内部,只是普通的用起来方便
3,除了基础的直接在标签内部赋值外,其他的基本上都有自己的标签体。
4,注意map集合,和Properties类型注入的特点
1,使用前,需要在头文件前加入两句话
xmlns:p="http://www.springframework.org/schema/p"<!--使用p标签时导入,等价于property -->
xmlns:c="http://www.springframework.org/schema/c"<!--使用c标签时导入,等价于constructor-arg
-->
2,用法
<!-- p命名空间注入,直接在标签体内部进行赋值,就相当于格式化-->
<!--p:name="caishan" 等价于 <property name="name" value="caishan "/> -->
<bean id="user" class="com.kuang.pojo.User" p:name="ppj" p:age="18"/>
<!-- c命名空间注入-->
<bean id="user2" class="com.kuang.pojo.User" c:name="牛天成" c:age="18"/>
1,单例模式(Spring默认机制)(scope=“singleton”)(只有一个对象)
<bean id="user2" class="com.kuang.pojo.User" c:name="牛天成" c:age="18" scope="singleton"/>
2,原型模式(每次从容器中get的时候,都会产生一个新对象)(scope=“prototype”)
<bean id="user2" class="com.kuang.pojo.User" c:name="牛天成" c:age="18" scope="prototype"/>
3,其余的request,session,application这些个只能在web开发中使用到
意义:可以不需要手动的给属性赋值(一般用于有引用型属性)
autowire字段选择装配方式
主要用于属性是对象类型的时候
7,1 使用byName自动装配(autowire=“byName”)
<!--
byName: 会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean的id属性
例:在该类中有一个People类的属性和setPeople的方法,那么xml中有一个id为people(忽略大小写)的bean,那么这个属性就自动和id为people的bean绑定。
-->
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="ppj"/>
</bean>
<!--byName的时候,需要保证所有bean的id唯一-->
7,2 使用byType自动装配(autowire=“byType”)
<!--
byType: 会自动在容器上下文中查找, 和自己对象属性类型相同的bean
例:在该类中有一个People类的属性,那么xml中有一个类型为People类的bean,那么这个属性就自动和class为People的bean绑定。
-->
<bean id="people" class="com.kuang.pojo.People" autowire="byType">
<property name="name" value="ppj"/>
</bean>
<!--byType的时候,需要保证所有bean的class唯一,使用byType可以不用写id-->
使用注解装配,需要先导入context约束,context依赖
<!--在头文件加入-->
xmlns:context="http://www.springframework.org/schema/context" <!--**-->
http://www.springframework.org/schema/context <!--**-->
https://www.springframework.org/schema/context/spring-context.xsd <!--**-->
<context:annotation-config/>//导入自动装配的依赖
</beans>
提前也要在spring中注册
除非自动装配的类也用注解进行了注册
注解加入的位置:
//可以加在属性的头上(注意:每一个属性都自己加自己的)
@Autowired(required = false)//如果定义@Autowired(required = false),说明这个对象可以为null,否则不允许为空(默认是true)
private Cat cat;
@Autowired//也可以不加后面的约束
private Cat cat;
//也可以直接加在set方法头上
//也可以忽略set方法,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byName默认是通过byType (就是说如果用注解自动装配可以不写set方法但是要在spring中配置,否则不用配置)
如果有多个同类的对象,则无法进行自动的绑定需要使用**@Qualifier(value = “绑定对象的ID名字”)**注解进行配套使用
<!--这是另一个配置注解,可以从byName,byType两种方式去匹配-->
@Resource
private Cat cat;
@Nullable 属性标记了这个注解,说明这个字段可以为null
小结:
@Resource和@Autowired的区别:
都是用来自动装配的,都可以放在属性字段上
@Autowired通过byType的方式实现,而且必须要求这个对象存在 【常用】
@Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到,就会报错
不同:@Autowired通过byType的方式实现 @Resource默认通过byName的方式实现
使用注解开发的第一步还是需要先导入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:component-scan base-package="包的全路径"/><扫描包>
// <context:annotation-config/>//导入的依赖
</beans>
2,需要在指定包的每一个类上加上这个注解**@Component** :意思是该包的对象就在spring容器中被创建了。
该对象的名字为类名的首字母小写形式,也可以在里面写上想要的名字
@Component("注册名") //等价于 <bean id="user" class="pojo.User">
public class User {
<!--需要给对象的属性赋值,则使用@Value("值")注解-->
//等价于 <property name="name" value="ppj"/>
@Value("ppj")
private String name;
}
3, 衍生的注解
@Componet有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
dao [@Repository]
service [@Service]
controller 【@Controller】
这4个注解的功能都是一样的(都等价于@Componet),都是代表将某个类注册到Spring中,装配Bean
4,自动装配注解
@Resource
@Autowired
5,作用域注解
@Scope(“prototype”) [代表该类是单例模式]
6,总结
xml与注解
最佳实践:
其中一个方法就是一个bean对象
//@Configuration代表这是一个配置类,就和我们之前看的beans.xml是一样的 @Configuration @ComponentScan("包名")//扫描包。等价于 <context:component-scan base-package="包的全路径"/> @Import(配置类名.class)//类似将多个xml文件导成一个 public class MyConfig { //注册一个bean,就相当于我们之前写的一个bean标签 //这个方法的名字,就相当于bean标签中的id属性(对象名) //这个方法的返回值,就相当于bean标签中的class属性(类名) @Bean //等价于<bean id="getUser" class="com.XXX.User"/> public User getUser(){ return new User(); //就是返回要注入到bean的对象 } } //第二个配置类 @Configuration public class MyConfig2 { }
调用时:获取池子的方法有所改变
如果完全使用了配置类方式去做,我们就只能通过AnnotationConfigApplicationContext来获取容器,括号里面写这个配置类的类名.class
public class MyTest {
@Test
public void test(){
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfigApplicationContext来获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(类名.class);
User user = context.getBean("getUser", User.class);
System.out.println(user);
}
}
这种纯java的配置方式,在springboot中随处可见!
注意:一个代理只能对应一个接口
代理模式的意义是:为了不改动原有代码【满足开放封闭-原则】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xQ18q3qK-1668096073684)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729125335472.png)]
角色分析:
代码步骤:
抽象角色:
//房子
public interface Room {
//租房
public void Rent();
}
真实角色:
//房东
public class Host implements Room {
@Override
public void Rent() {
System.out.println("我要出租房子");
}
}
代理角色:(继承接口)
//代理 public class Proxy { private Host host; public Proxy() { } //客户找代理时,指定需要哪一个房东的房子 public Proxy(Host host) { this.host = host; } public void Rent() { //租房 host.Rent(); Money(); } //代理负责收租 private void Money(){ System.out.println("代理收租"); } }
租客:
//租客
public class Me {
public static void main(String[] args) {
Host host=new Host();
//找到代理,告诉他我要租谁的房子
Proxy proxy=new Proxy(host);
//进行租房
proxy.Rent();
}
}
代理模式的好处:
缺点:
业务接口:(接口)
public interface UserService {
/*
需求: 在不修改原代码的情况下,添加日志打印信息
*/
public void add();
public void delete();
public void update();
public void query();
}
真实业务:(实现类)
public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("add方法"); } @Override public void delete() { System.out.println("delete方法"); } @Override public void update() { System.out.println("update方法"); } @Override public void query() { System.out.println("query方法"); } }
需求:在不改变原有代码的基础上,实现日志打印,借助代理
public class UserServiceProxy implements UserService{ @Override public void add() { log("add"); System.out.println("add==="); } @Override public void delete() { log("delete"); System.out.println("delete==="); } @Override public void update() { log("update"); System.out.println("update====="); } @Override public void query() { log("query"); System.out.println("query====="); } public void log(String msg){ System.out.println("[DEBUG]"+msg+"方法执行"); } }
测试:
public static void main(String[] args) {
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.add();
}
直接用代理对象实现同样的业务接口,打印日志信息,而不触及到原代码
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
基于接口----JDK动态代理
基于类: cglib
java字节码实现: javassit
需要了解2个类:Proxy===代理, InvocationHandler:调用处理程序(接口)
InvocationHandler
Proxy
动态代理的好处:
可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
公共也就交给代理角色!实现业务的分工
公共业务发生扩展的时候,方便集中管理
一个动态代理类代理的是一个接口,一般就是对应的一类业务
一个动态代理类可以代理多个类,只要是实现了同一个接口即可
可以直接封装,使用
public class ProxyInvocationHandler implements InvocationHandler{ private Object target;//需要代理的接口(object可以是具体的接口名,target可以是任意名字) public void SetTarget(Object target){ this.target=target; } //得到生成的代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass.getInterfaces,this); } //处理代理实例,返回结果(处理客户端选择执行的方法) //Method:方法 Object[]:应该是参数 Proxy:代理类 public Object invoke(Object Proxy,Method method,Object[] args)throws Throwable{ //其他代理类额外添加的方法,写在这里面 Object result =method.invoke(target,args);//执行选择的方法 return result; } }
调用:
public Static void main(String[] args){
//创建真实角色(这一步没变)
UserServiceImpl userService=new UserServiceImpl();
//创建代理角色
ProxyInvocationHandLer pih =new ProxyInvocationHandLer();//调用之前的自动生成代理类方法
pih.setTarget(userService);//将需要代理的真实角色传递给他
UserService proxy=(UserService)pih.getProxy();//创建代理类(UserService:接口名)
proxy.query();//利用该代理类调用方法
}
提供声明式事务;允许用户自定义切面
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …(用AOP插入的情况)
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
目标(Target):被通知对象。
代理(Proxy):向目标对象应用通知之后创建的对象。
切入点(PointCut):执行方法的位置
连接点(JointPoint):与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aiSxyMag-1668096073686)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729161213739.png)]
即AOP在不改变原有代码的情况下,去增加新的功能
使用AOP置入,需要导入一个依赖包[重点]
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
<scope>runtime</scope>
</dependency>
1,编写业务接口和实现类
public interface UserService { public void add(); public void delete(); public void update(); public void select(); } public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("add方法。。。"); } @Override public void delete() { System.out.println("delete方法。。。"); } @Override public void update() { System.out.println("update方法。。。"); } @Override public void select() { System.out.println("select方法。。。"); } }
2,编写增强类,后置和前置增强(Advisor)[继承不同的接口]
//MethodBeforeAdvice:前置增强
public class BeforeLog implements MethodBeforeAdvice {
//method: 要执行目标对象的方法
//args: 被调用方法的参数
//target: 目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法");
}
}
//AfterReturningAdvice:后置增强
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法"+returnValue);
}
}
3,将这些类注册到Spring容器中,并实现aop切入,导入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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop//导入的 https://www.springframework.org/schema/aop/spring-aop.xsd//导入的 "> <bean id="userService" class="com.kuang.service.UserServiceImpl"/> <bean id="beforeLog" class="com.kuang.log.BeforeLog"/> <bean id="afterLog" class="com.kuang.log.AfterLog"/> <!-- AOP配置 --> <aop:config> <!-- 配置切入点 expression:是一个表达式--> <aop:pointcut id="pointcut" //这个名字可以随便取 expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>//固定写法 execution(* 哪一个类.*全部方法(..)//代表多个参数) <!-- 执行环绕 advice-ref执行方法 . pointcut-ref切入点--> <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config> //aop:config 标签的完整意思:在UserServiceImpl这个实现类的所有方法中配置切入点,然后在执行这些方法时执行advice-ref定义的方法 </beans>
4.测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理的是接口,虽然绑定的对象是一个接口的实现类,但是返回值还是一个接口
UserService userService = (UserService) context.getBean("userService");
userService.delete();
}
}
1,将之前的增强类变为一个普通类,里面写多个方法
public class MyAspect {
//方法就是之前的各种增强类,名字随便起
public void before(){
System.out.println("before通知=====");
}
public void after(){
System.out.println("after通知=======");
}
}
2,在spring中配置
<!-- 方式二: 自定义切面类 -->
<bean id="myAspect" class="com.kuang.def.MyAspect"/>
<aop:config>
<!--aspect:自定义切面 ref要引用的类 -->//自定义方法必须用aop:aspect这个标签
<aop:aspect ref="myAspect">
<!-- 切入点 -->
<aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!-- 通知(要切入的方法) -->
<aop:before method="before" pointcut-ref="pointcut"/>
//我要切入ref这个类中的before()方法,在pointcut指定的切入点切入,什么时候切入?aop:before的时候
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
3,测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理的是接口
UserService userService = (UserService) context.getBean("userService");
userService.delete();
}
}
不需要导入注解的约束【因为不是用注解写对象】
只需要导入aop相关约束即可
在xml中需要新增一个标签
开启注解支持
<aop:aspectj-autoproxy/>
@Aspect //标注这个类是一个切面 public class AnnotationAspect { //前置通知 @Before("execution(* com.kuang.service.UserServiceImpl.*(..))") public void before(){ System.out.println("执行方法前===="); } //后置通知 @After("execution(* com.kuang.service.UserServiceImpl.*(..))") public void after(){ System.out.println("执行方法后====="); } //环绕通知 @Around("execution(* com.kuang.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前====="); jp.proceed(); //执行方法 System.out.println("环绕后====="); } }
mybatis是写接口,写mapper.xml文件,写SQL
Spring就是万物皆对象,每一个类都是一个对象,在beans.xml中实例化之后才可以使用
步骤:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y0VBwCly-1668096073686)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729180248262.png)]
导入相关jar包
junit
mybatis
mysql
spring
AOP
spring-jdbc【新的】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8PNVdPOm-1668096073687)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729180039423.png)]
mybatis-spring【新的】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4u8MewxF-1668096073687)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729180200901.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KyK3Ymev-1668096073687)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220729175925321.png)]
1,编写配置文件
2,测试
利用SqlSessionTemplate。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJKEh0Il-1668096073688)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730135529798.png)]
第一步:编写数据源
在spring的配置文件中编写以下代码
<!-- DataSource:使用Spring的数据源替换mybatis的配置 c3p0 dbcp druid
这里使用spring提供的jdbc: 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/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
第二步:创建SqlSessionFatory对象
<!-- SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定mybatis配置文件(这两句可不写)-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>//意思是:相当于绑定注册,绑定com/kuang/mapper/*.xml这个路径下的所有Mapper.xml
</bean>
第三步:创建sqlsession对象(在spring中叫sqlSessionTemplate)
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 只能用有参构造器注入sqlSessionFactory 因为它没有set方法 -->
<constructor-arg ref="sqlSessionFactory"/>
</bean>
//第二,第三步相当于之前写的mybatis工具类
如何使用?
1,需要给接口加实现类
在原来mybatis的基础上给mapper接口添加实现类(实现类去实现具体的调用步骤)
public class UserMapperImpl implements UserMapper {
private SqlSessionTemplate sqlSession;//在实现类中定义一个SqlSessionTemplate对象
public void setSqlSession(SqlSessionTemplate sqlSession) {//需要写一个set方法,一会方便在beans.xml中进行注入
this.sqlSession = sqlSession;
}
@Override//这就是类似指定调用的SQL语句
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//还是需要映射一个接口的对象调用方法执行SQL
List<User> userList = mapper.selectUser();//执行SQL
return userList;
}
}
2,将自己写的实现类,注入到spring中(创建一个实现类的对象)
<!-- 总的spring配置文件 -->
<bean id="UserMapperImpl" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>//将SQLsession对象注入
</bean>
3,测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
for (User user : userMapper.selectUser()) {
System.out.println(user);
}
}
}
遇见的错误
mybatis-config.xml里的mappers 要删了,
这个和 spring-dao的
<property name="mapperLocations"value="classpath:com/lzh/mapper/*.xml"/>
只能二选一!!!!!!不然会报错的,都是mapper的作用!
利用继承SqlSessionDaoSupport
两个点:不用再配置sqlsession对象,实现类继承
在实现类中写:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8cxGvJ2s-1668096073688)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730162524102.png)]
在beans.xml中写
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4nTgsIUz-1668096073688)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730162708466.png)]
相当于省略了beans.xml中配置sqlsession的步骤
spring中的事务管理分为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjhFgLkD-1668096073689)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220730170603636.png)]
步骤:
1,配置声明式事务(开启事务管理器)
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--这是死代码 ,dataSource:数据源-->
2,结合AOP实现事务的织入
<!--1, 导入事务的约束 (头文件处)--> //注意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:tx="http://www.springframework.org/schema/tx"//导入的 xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx//导入的 https://www.springframework.org/schema/tx/spring-tx.xsd //导入的 "> <!--2, 配置事务通知(方法) --> <!-- transactionManager步骤一所配置的bean --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 给哪些方法配置事务 --> <!-- 配置事务的传播特性: propagation=“required” spring默认事务 --> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/>//所有add方法配置事务 意思是:给所有的add方法配置REQUIRED类型的事务 <tx:method name="delete" propagation="REQUIRED"/>//所有delete方法配置事务 <tx:method name="query" read-only="true"/>//read-only表示query类的事务无法对数据库进行增删改 <tx:method name="*"/>//所有方法配置事务 </tx:attributes> </tx:advice> <!--3,配置事务切入(切入点) --> <aop:config> <aop:pointcut id="txPoint" expression="execution(* com.kuang.mapper.*.*(..))"/>切入点 <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>//切入的方法 </aop:config>
AOP:切面,通知,切入点
为什么需要事务?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。