IOC(接口)
- 1.IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。
- 2.Spring提供IOC容器实现的两种方式:(两个接口)
- (1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用。
- 特点:加载配置文件的时候不会创建对象,在获取对象(使用)才去创建对象。
- (2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般是由开发人员进行使用。
- 特点:加载配置文件时就会把配置文件对象进行创建。
- (1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用。
IOC操作Bean管理(概念)
- 1.什么是Bean管理?
- (0)Bean管理指的是两个操作
- (1)Spring 创建对象
- (2)Spring 注入对象
- 2.Bean管理操作有两种方式
- (1)基于xml配置文件方式实现
<!--(1)在Spring配置文件中,使用Bean标签,标签里面添加对应属性,就可以实现对象创建--> <!--配置User对象创建--> <bean id="User" class="com.Gby.pojo.User"></bean>
-
在bean标签有很多属性,介绍常用的属性
id属性:唯一标识
class属性:类全路径(包类路径)
name属性:唯一标识(可以使用特殊符号,如:"/")
-
创建对象时候,默认也是执行无参数构造方法,完成对象创建
-
- (2)基于注解方式实现
- (1)DI:依赖注入,就是注入属性
- 第一种注入方式:使用set方法进行注入
- 注入方式:在Spring配置文件配置对象创建,配置属性注入
<!--1.创建对象--> <bean id="Book" class="com.Gby.pojo.Book"> <!--2.注入属性--> <property name="username" value="易筋经"/> <property name="author" value="悟空"/> </bean>
- 第二种注入方式:使用有参构造进行注入
- 注入方式:在Spring配置文件配置对象创建,配置属性注入
<!--2.有参构造--> <bean id="Book" class="com.Gby.pojo.Book"> <constructor-arg name="author" value="wukong"/> <constructor-arg name="username" value="yijinjing"/> <!--也可以通过索引值进行注入--> <!--<constructor-arg index="0" value="111"/>--> </bean>
- 第一种注入方式:使用set方法进行注入
- (1)DI:依赖注入,就是注入属性
- (3)p名称空间注入
- (1)使用p名称空间注入,可以简化基于xml配置方式
- 第一步添加p名称空间在配置文件中
<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"> </beans>
- 第二步,进行属性注入,在bean标签里面进行操作
<bean id="Book" class="com.Gby.pojo.Book" p:author="wuyu" p:username="mieshiwuxiu"/>
- 第一步添加p名称空间在配置文件中
- (1)使用p名称空间注入,可以简化基于xml配置方式
- (1)基于xml配置文件方式实现
IOC操作Bean管理(xml注入其他类型属性)
-
1.字面量
- (1)null值
<property name="author"> <null/> </property>
- (2)属性值包括特殊符号
<property name="author"> <!--属性值包括特殊符号 1.把<>进行转义 < , > 2.把带有特殊符号内容写到CDATA --> <value><![CDATA[<<南京>>]]></value> </property>
- (1)null值
-
2.注入属性-外部Bean
- (1)创建两个类service类和dao类
public class UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void add(){ System.out.println("service add ...."); /*//创建UserDao对象 UserDao userDao = new UserDaoImpl(); userDao.updata();*/ } }
public class UserDaoImpl implements UserDao{ @Override public void updata() { System.out.println("Dao updata ....."); } }
public interface UserDao { public void updata(); }
- (2)在service调用dao里面的方法
- (3)在Spring配置文件中进行配置
<!--1.service和dao对象创建--> <bean id="UserService" class="com.Gby.Service.UserService"> <!--注入UserDao对象 name属性值:类里面属性名称 ref:创建userdao对象Bean标签id值--> <property name="UserDao" ref="UserDaoImpl"/> </bean> <bean id="UserDaoImpl" class="com.Gby.Dao.UserDaoImpl"/>
- (1)创建两个类service类和dao类
-
3.注入属性-内部Bean和级联赋值
- (1)一对多关系:部门和员工,一个部门有多个员工,一个员工属于一个部门,部门是一,员工是多
- (2)在实体类之间表示一对多的关系
//部门类 public class Dept { private String name; public Dept(String name) { this.name = name; } public Dept() { } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Dept{" + "name='" + name + '\'' + '}'; } }
//员工类 public class Emp { private String ename; private String gender; private Dept dept; public void setDept(Dept dept) { this.dept = dept; } public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } public Emp() { } @Override public String toString() { return "Emp{" + "ename='" + ename + '\'' + ", gender='" + gender + '\'' + ", dept=" + dept + '}'; } public void add(){ System.out.println(11111); } }
- (3)在Spring配置文件中进行配置
<!--内部Bean--> <bean id="Emp" class="com.Gby.Bean.Emp"> <!--现设置两个普通的属性--> <property name="ename" value="luck"/> <property name="gender" value="女"/> <!--设置对象类型属性--> <property name="dept"> <bean id="dept" class="com.Gby.Bean.Dept"> <property name="name" value="安保部"></property> </bean> </property> </bean>
-
4.注入属性-级联赋值
- (1)第一种写法
<!--级联赋值--> <bean id="Emp" class="com.Gby.Bean.Emp"> <!--现设置两个普通的属性--> <property name="ename" value="luck"></property> <property name="gender" value="女"></property> <!--级联赋值--> <property name="dept" ref="dept"></property> </bean> <bean id="dept" class="com.Gby.Bean.Dept"> <property name="name" value="财务部"></property> </bean>
- (2)第二种写法
<!--级联赋值--> <bean id="Emp" class="com.Gby.Bean.Emp"> <!--现设置两个普通的属性--> <property name="ename" value="luck"></property> <property name="gender" value="女"></property> <!--级联赋值--> <property name="dept" ref="dept"></property> <!--需要在Emp类中生成一下dept的get方法--> <property name="dept.name" value="技术部"/> </bean> <bean id="dept" class="com.Gby.Bean.Dept"> <property name="name" value="财务部"></property> </bean>
- (1)第一种写法
IOC操作Bean管理(xml注入集合属性)
-
1.注入数组类型属性
-
2.注入List集合类型属性
-
3.注入Map集合类型属性
-
(1)创建类,定义数组,list、map、set类型属性,生成对应set方法
public class Stu { //数组类型属性 private String[] courses; //list集合类型属性 private List<String> list; //map集合类型属性 private Map<String,String> map; //set集合类型属性 private Set<String> sets; public void setSets(Set<String> sets) { this.sets = sets; } public void setMap(Map<String, String> map) { this.map = map; } public void setList(List<String> list) { this.list = list; } public void setCourses(String[] courses) { this.courses = courses; } public Stu() { } }
-
(2)在spring配置文件进行配置
<!--集合类型属性的注入--> <bean id="Stu" class="com.Gby.collectiontype.Stu"> <!--数组类型属性注入--> <property name="courses"> <array> <value>java</value> <value>Mysql</value> </array> </property> <!--list集合类型属性注入--> <property name="list"> <list> <value>zhangsan</value> <value>xiaosan</value> </list> </property> <!--map类型属性注入--> <property name="map"> <map> <entry key="JAVA" value="java"/> <entry key="PHP" value="php"/> </map> </property> <!--set类型属性注入--> <property name="sets"> <set> <value>Mysql</value> <value>VUE</value> </set> </property> </bean>
-
-
4.在集合里面设置对象类型值
<!--创建多个course对象--> <bean id="course1" class="com.Gby.collectiontype.Course"> <property name="name" value="spring5"/> </bean> <bean id="course2" class="com.Gby.collectiontype.Course"> <property name="name" value="Mybatis"/> </bean> <!--注入list集合类型,值是对象--> <property name="courseList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property>
-
5.把集合注入部分提取出来
- (1)在spring配置文件中引入名称空间 util
<?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">
- (2)使用util标签完成list集合注入提取
<!--1.提取list集合类型属性注入--> <util:list id="bookList"> <value>1</value> <value>2</value> <value>3</value> </util:list> <!--2.提取list集合类型属性注入使用--> <bean id="book" class="com.Gby.collectiontype.Book"> <property name="book" ref="bookList"></property> </bean>
- (1)在spring配置文件中引入名称空间 util
IOC操作Bean管理(FactoryBean)
- 1.Spring有辆各种类型bean,一种普通bean,另外一种工厂Bean(FactoryBean)
- 2.普通Bean:在配置文件中定义bean类型就是返回类型
- 3.工厂Bean:在配置文件定义Bean类型可以和返回类型不一样
-
第一步创建类,让这个类作为工厂bean,实现接口FactoryBean
public class mybean implements FactoryBean<Course> { //定义返回bean @Override public Course getObject() throws Exception { Course course = new Course(); course.setName("abc"); return course; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }
-
第二步实现接口里面的方法,在实现的方法中定义返回的bean类型
public void Stu3(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Course course = context.getBean("mybean", Course.class); System.out.println(course); }
-
IOC操作Bean管理(bean作用域)
-
1.在Spring里面,设置创建bean实例是单实例还是多实例
-
2.在Spring里面,默认情况下,bean是单实例对象
@Test public void Stu3(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Course course = context.getBean("mybean", Course.class); System.out.println(course); System.out.println(course); } com.Gby.collectiontype.Course@3cb1ffe6 com.Gby.collectiontype.Course@3cb1ffe6
-
3.如何设置单实例还是多实例
-
(1)在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
- 1.默认值,singleton,表示单实例对象
- 2.多实例,prototype,表示多实例对象
<bean id="Student" class="com.Gby.Pojo.Student" scope="prototype"> <property name="student" value="1231"/> </bean>
@Test public void test(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); Student student = context.getBean("Student", Student.class); Student student1 = context.getBean("Student", Student.class); System.out.println(student); System.out.println(student1); } com.Gby.Pojo.Student@6043cd28 com.Gby.Pojo.Student@cb51256
-
(2).singleton和prototype区别
-
(1)设置scope的值是singleton时,加载配置文件时候就会创建单实例对象。
设置scope值是prototype的时候,在调用getBean方法的时候创建多实例对象
-
-
IOC操作Bean管理(bean生命周期)
-
1.生命周期
- (1)从对象创建到对象销毁的过程
-
2.bean的生命周期
- (1)通过构造器创建bean实例(无参数构造)
- (2)为bean的属性设置值和对其他bean引用(调用set方法)
- (3)把bean实例传递bean后置处理器的方法
- (4)调用bean的初始化的方法(需要进行配置)
- (5)把bean实例传递bean后置处理器方法
- (6)bean可以使用了(对象获取到了)
- (7)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
-
3.演示bean的生命周期
public class Student { private String student; public Student() { System.out.println("第一步,执行无参数构造创建bean实例"); } public void setStudent(String student) { this.student = student; System.out.println("第二步,调用set方法设置属性值"); } //创建初始化方法 public void initMethod(){ System.out.println("第三步,调用初始化方法"); } //创建销毁方法 public void distroyMethod(){ System.out.println("第五步,销毁方法"); } }
<!--init-method:初始化方法,destroy-method:销毁方法--> <bean id="Student" class="com.Gby.Pojo.Student" init-method="initMethod" destroy-method="distroyMethod"> <property name="student" value="1231"/> </bean>
public void test1(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); Student student = context.getBean("Student", Student.class); System.out.println("第四步获取对象"); System.out.println(student); //手动销毁Bean实例 context.close(); }
-
4.bean的后置处理器
- (1)通过构造器创建bean实例(无参数构造)
- (2)为bean的属性设置值和对其他bean引用(调用set方法)
- (3)把bean实例传递bean后置处理器的方法(postProcessBeforeInitialization)
- (4)调用bean的初始化的方法(需要进行配置)
- (5)把bean实例传递bean后置处理器方法(postProcessAfterInitialization)
- (6)bean可以使用了(对象获取到了)
- (7)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
-
5.演示添加后置处理器效果
- (1)创建类,实现接口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.Gby.Pojo.MyBeanPost"></bean>
第一步,执行无参数构造创建bean实例 第二步,调用set方法设置属性值 在初始化之前执行的方法 第三步,调用初始化方法 在初始化之后执行的方法 第四步获取对象 com.Gby.Pojo.Student@46daef40 第五步,销毁方法
IOC操作Bean管理(xml自动装配)
- 1.什么是自动装配
- (1)根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
- 2.演示自动装配过程
- (1)根据属性名称自动注入
<!--实现自动装配 bean标签属性autowire,配置自动装配 autowire属性常用两个值 byName根据属性名称注入 byType根据属性类型注--> <bean id="Emp" class="com.Gby.autowire.Emp" autowire="byName"> <!--<property name="dept" ref="Dept"></property>--> </bean> <bean id="Dept" class="com.Gby.autowire.Dept"></bean>
- (2)根据属性类型自动注入
<bean id="Emp" class="com.Gby.autowire.Emp" autowire="byType"> <!--<property name="dept" ref="Dept"></property>--> </bean> <bean id="Dept" class="com.Gby.autowire.Dept"></bean>
- (1)根据属性名称自动注入
IOC操作Bean管理(外部属性文件)
- 1.直接配置数据库信息
- (1)引入德鲁伊连接池依赖jar包
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency>
- (2)配置德鲁伊数据库
<!--直接配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/user"/> <property name="username" value="root"/> <property name="password" value="***"/> </bean>
- (1)引入德鲁伊连接池依赖jar包
- 2.引入外部属性文件配置数据库连接池
- (1)创建外部属性文件,properties格式文件,数据库信息
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/user prop.username=root prop.password=***
- (2)把外部properties属性文件引入到Spring配置文件中
- 引入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">
- 在spring配置文件使用标签引入外部属性文件
<!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"/> <property name="url" value="${prop.url}"/> <property name="username" value="${prop.username}"/> <property name="password" value="${prop.password}"/> </bean>
- 引入context名称空间
- (1)创建外部属性文件,properties格式文件,数据库信息
IOC操作Bean管理(基于注解方式)
- 1.什么是注解
- (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
- (2)使用注解,注解作用在类的上面,方法上面,属性上面
- (3)使用注解的目的:简化xml配置
- 2.Spring针对Bean管理中创建对象提供注解
- (1)@Component
- (2)@Service
- (3)@Controller
- (4)@Repository
上面的四个注解功能都是一样的,都可以用来创建bean实例
- 3.基于注解方式实现对象的创建
- (1)第一步,引入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency>
- (2)第二步,开启组件扫描
<!--开启组件扫描 1.如果扫描多个包,多个包使用逗号隔开 2.扫描包上层目录--> <context:component-scan base-package="com.Gby"></context:component-scan>
- (3)第三步创建类,在类上面添加创建对象的注解
//在注解里面value属性值可以省略不写 //默认值是类名称,首字母小写 UserService-->userService @Component(value = "userService") public class UserService { public void add(){ System.out.println("service add..."); } }
- (1)第一步,引入依赖
- 4.开启组件扫描细节配置
<!--示例1 use-default-filters表示现在不使用默认filter,自己配置filter annotation注解 exclude-filter,设置扫描哪些内容 --> <context:component-scan base-package="com.Gby" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--示例2 下面配置扫描包所有内容 context:exclude-filter:设置哪些内容不进行扫描 --> <context:component-scan base-package="com.Gby"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
- 5.基于注解方式实现属性注入
-
(1)@AutoWired:根据属性类型进行自动装配
- 第一步把Service和dao对象创建,在service和dao类添加创建对象注解
- 第二步在service注入dao对象,在service类添加dao类型的属性,在属性上面使用注解
@Service(value = "userService") public class UserService { //定义dao类型属性 //不需要添加set方法 //添加注入属性的注解 @Autowired private UserDao userDao; public void add(){ System.out.println("service add..."); userDao.add(); } }
-
(2)@Qualifier:根据属性名称进行注入
- 这个@Qualifier注解的使用,和上面的@AutoWired一起使用
//在注解里面value属性值可以省略不写 //默认值是类名称,首字母小写 UserService-->userService @Service(value = "userService") public class UserService { //定义dao类型属性 //不需要添加set方法 //添加注入属性的注解 @Autowired//根据类型进行注入 @Qualifier(value = "userDaoImpl") private UserDao userDao; public void add(){ System.out.println("service add..."); userDao.add(); } }
- 这个@Qualifier注解的使用,和上面的@AutoWired一起使用
-
(3)@Resource:可以根据类型注入,可以根据名称注入
//@Resource //根据类型进行注入 @Resource(name = "userDaoImpl") private UserDao userDao;
-
(4)Value:注入普通类型属性
@Value(value = "abc") private String name;
-
- 6.完全注解开发
- (1)创建配置类,替代xml配置文件
@Configuration//作为配置类,替代xml配置文件 @ComponentScan(basePackages = {"com.Gby"}) public class SpringConfig { }
- (2)编写测试类
@Test public void test1(){ ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); }
- (1)创建配置类,替代xml配置文件
AOP(概念)
- 1.什么是AOP
- (1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发速率。
- (2)通俗描述:不通过源代码方式,在主干功能里面添加新功能
AOP(底层原理)
- 1.AOP底层使用动态代理
- (1)有两种情况的动态代理
- 第一种情况,有接口情况,使用JDK动态代理
- 创建接口实现类代理对象,增强类的方法
- 第二种情况,没有接口情况,使用CGLIB动态代理
- 第一种情况,有接口情况,使用JDK动态代理
- (1)有两种情况的动态代理
AOP(JDK动态代理)
- 1.使用JDK动态代理,使用Proxy类里面的方法创建代理对象
- (1)调用newProxyInstance方法
static Object newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h) //返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
-
方法有三个参数:
第一参数,类加载器。 第二参数,增强方法所在类,这个类实现的接口,支持多个接口 第三参数,实现这个接口InvocationHandler,创建代理对象,写增强的方法
-
- (1)调用newProxyInstance方法
- 2.编写JDK动态代理代码
- (1)创建接口,定义方法
public interface UserDao { public int add(int a,int b); public String update(String id); }
- (2)创建接口实现类,实现方法
public class UserDaoImpl implements UserDao{ @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } }
- (3)使用Proxy类创建接口代理对象
public class JdkProxy { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); UserDao o = (UserDao) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int add = o.add(1, 2); System.out.println(add); } } //创建代理对象代码 class UserDaoProxy implements InvocationHandler{ //1.把创建的是谁的代理对象,把谁传递过来 //有参数构造传递 private Object object; public UserDaoProxy(Object object){ this.object=object; } //增强的逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("方法之前执行..."+method.getName()+":传递的参数"+ Arrays.toString(args)); //被增强的方法执行 Object invoke = method.invoke(object, args); //方法之后 System.out.println("方法之后执行"+object); return invoke; } }
- (1)创建接口,定义方法
AOP(术语)
- 1.连接点
- 类里面那些方法可以被增强,这些方法称为连接点
- 2.切入点
- 实际被增强的方法,称为切入点
- 3.通知(增强)
- 实际增强的逻辑部分称为通知(增强)
- 通知有多种类型
前置通知 后置通知 环绕通知 异常通知 最终通知 finally
- 3.切面
- 切面是动作,把通知应用到切入点过程
AOP操作(准备)
- 1.Spring框架一般都是基于AspectJ实现Aop操作
- (1)什么是AspectJ
- AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行Aop操作
- (1)什么是AspectJ
- 2.基于AspectJ实现AOP操作
- (1)基于xml配置文件
- (2)基于注解方式实现(使用)
- 3.在项目工程里面引入AOP相关依赖
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
- 4.切入点表达式
- (1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
- (2)语法结构:execution( [权限修饰符] [返回类型] [类全路径] ([参数列表]))
-
举例1:对com.Gby.dao.BookDao类里面的add进行增强
execution(* com.Gby.dao.BookDao.add(…))
-
举例2:对com.Gby.dao.BookDao类里面的所有方法进行增强
execution(* com.Gby.dao.BookDao.*(…))
-
举例3:对com.Gby.dao包里面的所有类,类里面的所有方法进行增强
execution(* com.Gby.dao.* .*(…))
-
AOP操作(AspectJ注解)
- 1.创建类,在类里面定义方法
public class User { public void add(){ System.out.println("add......."); } }
- 2.创建增强类(编写增强逻辑)
- (1)在增强类里面,创建方法,让不同的方法代表不同的方法类型
//增强的类 public class UserProxy { //前置通知 public void before(){ System.out.println("before....."); } }
- (1)在增强类里面,创建方法,让不同的方法代表不同的方法类型
- 3.进行通知的配置
-
(1)在Spring配置文件中,开启注解扫描
<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="com.Gby"></context:component-scan> </beans>
-
(2)使用注解创建User和UserProxy对象
//增强的类 @Component public class UserProxy { //前置通知 public void before(){ System.out.println("before....."); } }
//被增强的类 @Component public class User { public void add(){ System.out.println("add......."); } }
-
(3)在增强的类上面添加注解@Aspect
//增强的类 @Component @Aspect//生成代理对象 public class UserProxy { //前置通知 public void before(){ System.out.println("before....."); } }
-
(4)在Spring配置文件中开启生成代理对象
<!--开启注解扫描--> <context:component-scan base-package="com.Gby"/> <!--开启Aspect生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
- 4.配置不同类型的通知
- (1)在增强类的里面,在作为通知的方法上面添加通知类型注解,使用切入点表达式配置
//增强的类 @Component @Aspect//生成代理对象 public class UserProxy { //前置通知 @Before(value = "execution(* com.Gby.aop.User.add(..))") public void before(){ System.out.println("before....."); } //最终通知 @After(value = "execution(* com.Gby.aop.User.add(..))") public void after(){ System.out.println("after...."); } //方法返回值之后执行 @AfterReturning(value = "execution(* com.Gby.aop.User.add(..))") public void AfterReturning(){ System.out.println("AfterReturning......."); } //异常通知 @AfterThrowing(value = "execution(* com.Gby.aop.User.add(..))") public void AfterThrowing(){ System.out.println("AfterThrowing........"); } //环绕通知 @Around(value = "execution(* com.Gby.aop.User.add(..))") public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前......"); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); } }
- (1)在增强类的里面,在作为通知的方法上面添加通知类型注解,使用切入点表达式配置
- 5.形同切入点的提取
//相同切入点抽取 @Pointcut(value = "execution(* com.Gby.aop.User.add(..))") public void Pointcut(){} //前置通知 @Before(value = "execution(* com.Gby.aop.User.add(..))") public void before(){ System.out.println("before....."); } //最终通知 @After(value = "Pointcut()") public void after(){ System.out.println("after...."); }
- 6.有多个增强类多同一个方法进行增强,设置增强类优先级
- (1)在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高
@Component @Aspect @Order(2) public class PersonProxy { //前置通知 @Before(value = "execution(* com.Gby.aop.User.add(..))") public void before(){ System.out.println("person before....."); } }
- (1)在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高
- 7.完全使用注解开发
- (1)创建配置类,不需要创建xml配置文件
@Configuration @ComponentScan @EnableAspectJAutoProxy(proxyTargetClass = true) public class ConfigAop { }
- (1)创建配置类,不需要创建xml配置文件
AOP操作(AspectJ配置文件)
-
1.创建两个类,增强类和被增强类,创建方法
-
2.在Spring配置文件中创建两个类对象
<!--创建对象--> <bean id="Book" class="com.Gby.aopxml.Book"/> <bean id="BookProxy" class="com.Gby.aopxml.BookProxy"/>
-
3.在Spring配置文件中配置切入点
<!--配置aop增强--> <aop:config> <!--切入点--> <aop:pointcut id="p" expression="execution(* com.Gby.aopxml.Book.buy(..))"/> <!--配置切面--> <aop:aspect ref="BookProxy"> <!--增强作用在具体的方法上--> <aop:before method="before" pointcut-ref="p"/> </aop:aspect> </aop:config>
JdbcTemplate(概念和准备)
- 1.什么是JdbcTemplate
- (1)Spring框架对Jdbc进行封装,使用JdbcTemplate方便对数据库操作
- 2.准备工作
-
(1)引入相关的jar包
<!--数据库驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- 数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <!--Servlet - JSP --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!--Spring--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
-
(2)在Spring配置文件配置数据库连接池
<!--直接配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/book"/> <property name="username" value="root"/> <property name="password" value="***"/> </bean>
-
(3)配置JDBCTemplate对象,注入DataSource
<!--jdbcTemplate对象--> <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean>
-
(4)创建service类,创建dao类,在dao注入JDBCTemplate对象
- xml配置文件
<!--开启组件扫描--> <context:component-scan base-package="com.Gby" ></context:component-scan>
- Service
@Service(value = "bookService") public class BookService { //注入dao @Autowired private BookDao bookDao; }
- Dao
@Repository public class BookDaoImpl implements BookDao{ //注入jdbcTemplate @Autowired private JdbcTemplate jdbcTemplate; }
-
JDBCTemplate操作数据库(添加)
- 1.对应数据库创建实体类
public class User { private String userId; private String username; private String ustatus; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUstatus() { return ustatus; } public void setUstatus(String ustatus) { this.ustatus = ustatus; } public User() { } @Override public String toString() { return "User{" + "userId='" + userId + '\'' + ", username='" + username + '\'' + ", ustatus='" + ustatus + '\'' + '}'; } }
- 2.编写service和dao
-
(1)在dao进行数据库添加操作
@Repository public class BookDaoImpl implements BookDao{ //注入jdbcTemplate @Autowired private JdbcTemplate jdbcTemplate; @Override public void add(User user) { //创建sql语句 String sql = "insert into t_user values(?,?,?)"; //调用方法实现 int update = jdbcTemplate.update(sql, user.getUserId(), user.getUsername(), user.getUstatus()); System.out.println(update); } }
-
(2)调用JDBCTemplate对象里面update方法实现添加操作
update(String sql,Object... args) 有两个参数,第一个参数:sql语句,第二个参数:可变参数,设置sql语句值
-
- 3.编写测试类进行数据库添加操作
@Test public void add(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("AppliCationContext.xml"); BookService bookService = context.getBean("bookService", BookService.class); User user = new User(); user.setUserId("1"); user.setUsername("java"); user.setUstatus("a"); bookService.addBook(user); }
JDBCTemplate操作数据库(删除,修改)
- 1.修改数据库数据
@Override public void update(User user) { String sql = "update t_user set username=?,ustatus=? where user_id = ?"; Object[] args = {user.getUsername(),user.getUstatus(),user.getUserId()}; int update = jdbcTemplate.update(sql, args); System.out.println(update); }
- 2.删除数据库信息
@Override public void delete(int id) { String sql = "delete from t_user where user_id = ?"; int update = jdbcTemplate.update(sql, id); System.out.println(update); }
JDBCemplate操作数据库(查询返回某个值)
- 1.查询表里面有多少条记录,返回是某个值
- 2.使用JDBCTemplate实现查询返回某个值代码
queryForObject(String sql,Class<T> requiredType) 有两个参数,第一个参数:sql语句,第二个参数,返回类型calss
@Override public int insert(){ String sql = "select count(*) from t_user"; Integer integer = jdbcTemplate.queryForObject(sql, Integer.class); return integer; }
- 3.这里可能会出现的问题
出现这样的报错java.lang.NoSuchMethodError: org.springframework.dao.support.DataAccessUtils.nullableSingleResult(Ljava/util/Collection;)Ljava/lang/Object; 是因为Spring相关的jar包版本的问题,解决办法,把spring相关的jar包改成统一的版本。(建议在加载spring相关的jar时,就用统一的版本,可能有时候不会出错,为了避免此类的错误,还是改成一样版本的)
JDBCTemplate操作数据库(查询返回对象)
- 1.场景:查询图书的详情
- 2.JDBCTemplate实现查询返回对象
queryForObject(String sql,RowMapper<T> rowMapper,Object... args) //有三个参数,第一个参数:sql语句 //第二个参数:rowMapper,是接口,返回不同类型数据,使用这个接口里面实现类完成数据封装 //第三个参数:sql语句值 @Override public User findBookInfo(String id) { String sql = "select * from t_user where user_id = ?"; User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id); return user; }
JDBCTemplate操作数据库(查询返回集合)
- 1.场景:查询图书列表分页
- 2.调用JDBCTemplate方法实现查询返回集合
@Override public List<User> findAll() { String sql = "select * from t_user"; List<User> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class)); return query; }
JBCTemplate操作数据库(批量操作)
- 1.批量操作:操作表里面多条记录
- (1)JBCTemplate实现批量添加操作
batchUpdate(String sql,List<Object[]> batchArgs) //第一个参数:sql语句,第二个参数:list集合,添加多条记录的数据 @Override public void batchAddBook(List<Object[]> batchArgs) { String sql = "insert into t_user values(?,?,?)"; int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs); System.out.println(Arrays.toString(ints)); } //测试类批量操作 List<Object[]> batchArgs = new ArrayList<>(); Object[] o1 = {"4","mysql","a"}; Object[] o2 = {"5","vue","b"}; Object[] o3 = {"6","spring","a"}; batchArgs.add(o1); batchArgs.add(o2); batchArgs.add(o3); bookService.batchAdd(batchArgs);
- (2)JBCTemplate实现批量修改操作
@Override public void batchUpdate(List<Object[]> batchArgs) { String sql = "update t_user set username=?,ustatus=? where user_id = ?"; int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs); System.out.println(ints); }
- (3)JBCTemplate实现批量删除操作
@Override public void batchDelete(List<Object[]> batchArgs) { String sql = "delete from t_user where user_id = ?"; int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs); System.out.println(Arrays.toString(ints)); }
- (1)JBCTemplate实现批量添加操作
事务操作(事务概念)
- 1.什么是事务
- (1)事务是数据库操作最基本单元,逻辑上的一组操作,要么都成功,如果有一个失败所有操作都失败
- (2)典型场景:银行转账
- 2.事物的四个特性(ACID)
- (1)原子性:一个事务包含多个操作,这些操作要么全部执行,要么全都不执行。
- (2)一致性:一个提交更新的事务的结果被另一个读操作的事务获取的程度,以达到一致性。
- (3)隔离性:并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。
- (4)持久性:事务提交后,对系统的影响是永久的。
事务操作(搭建事务操作环节)
-
1.创建数据库表,添加记录
CREATE TABLE `book`.`t_account`( `id` VARCHAR(20) NOT NULL, `username` VARCHAR(50), `money` INT, PRIMARY KEY (`id`) ) ENGINE=INNODB CHARSET=utf8;
-
2.创建service,搭建dao,完成对象创建和注入关系
- service注入dao,在dao注入JDBCTemplate,JDBCTemplate在注入DateSource
@Service public class UserService { //注入dao @Autowired private UserDao userDao; //转账方法 public void accountMoney(){ //lucy少一百 userDao.reduceMoney(); //mary多一百 userDao.addMoney(); } }
-
3.在Dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)
@Repository public class UserDaoImpl implements UserDao{ @Autowired private JdbcTemplate jdbcTemplate; @Override public void addMoney() { String sql = "update t_account set money=money+? where username = ?"; jdbcTemplate.update(sql,100,"mary"); } @Override public void reduceMoney() { String sql = "update t_account set money=money-? where username = ?"; jdbcTemplate.update(sql,100,"lucy"); } }
-
4.上面代码,如果正常执行没有问题,但是如果代码在执行过程中出现了异常
@Service public class UserService { //注入dao @Autowired private UserDao userDao; //转账方法 public void accountMoney(){ //lucy少一百 userDao.reduceMoney(); //模拟异常 int i= 10/0; //mary多一百 userDao.addMoney(); } }
-
5.问题解决
- (1)使用事务进行解决
- (2)事务操作过程
//转账方法 public void accountMoney(){ try{ //第一步,开启事务操作 //第二步,进行业务操作 //lucy少一百 userDao.reduceMoney(); //模拟异常 int i= 10/0; //mary多一百 userDao.addMoney(); //第三步,没有异常提交事务 }catch (Exception e){ //第四步,出现异常,事务回滚 e.printStackTrace(); } }
事务操作(Spring事务管理介绍)
- 1.事务添加到JAVAEE三层架构里面的Service层(业务逻辑层)
- 2.在Spring里面进行事务管理操作
- (1)有两种方式:编程式事务管理和声明式事务管理(使用)
- 3.声明式事务管理
- (1)基于注解方式
- (2)基于xml配置文件方式
- 4.在Spring进行声明式事务管理,底层使用Aop
- 5.Spring事务管理API
- (1)提供了一个接口,代表事务管理器,这个接口针对不同框架提供了不同的实现类
事务操作(注解声明式事务管理)
- 1.在spring配置文件配置事务管理器
<!--创建事务管理器--> <bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"></property> </bean>
- 2.在Spring配置文件,开启事务注解
- (1)在Spring配置文件引入名称空间tx
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
- (2)开启事务注解
<tx:annotation-driven transaction-manager="TransactionManager"></tx:annotation-driven>
- (3)在Service类上面(获取Service类里面方法上面)添加事务注解
- @Transactional,这个注解添加到类上面,也可以添加到方法上面
- 如果把这个注解添加类上面,这个类里面所有的方法都添加事务
- 如果把这个注解添加方法上面,为方法添加了事务
@Service @Transactional public class UserService {}
- (1)在Spring配置文件引入名称空间tx
事务操作(声明式事务管理参数配置)
-
此处文章链接链接
-
在Service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
-
当类中某些方法不需要事物时:
@Transactional public class TestServiceBean implements TestService { private TestDao dao; public void setDao(TestDao dao) { this.dao = dao; } @Transactional(propagation =Propagation.NOT_SUPPORTED) public List getAll() { return null; } }
-
事物传播行为介绍:
@Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下) @Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务 @Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务 @Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常 @Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反) @Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务. @Transactional(propagation=Propagation.NESTED) :如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行。
-
事物超时设置:@Transactional(timeout=30) //默认是30秒
-
事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用 @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读) @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读) @Transactional(isolation = Isolation.SERIALIZABLE):串行化 MYSQL: 默认为REPEATABLE_READ级别 SQLSERVER: 默认为READ_COMMITTED
- 脏读 : 一个事务读取到另一事务未提交的更新数据
- 不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
- 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
- 读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
- 幻读 : 一个事务读到另一个事务已提交的insert数据
-
@Transactional注解中常用参数说明
readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true) rollbackFor 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如: 指定单一异常类:@Transactional(rollbackFor=RuntimeException.class) 指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class}) rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如: 指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException") 指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"}) noRollbackFor 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如: 指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class) 指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class}) noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如: 指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException") 指定多个异常类名称: @Transactional(noRollbackForClassName={"RuntimeException","Exception"}) propagation 该属性用于设置事务的传播行为,具体取值可参考事物传播行为介绍。 例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置 timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时
-
注意的几点:
- 1、@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
- 2、用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚; 而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时, 需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)如下:
@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚 public void methodName() { throw new Exception("注释"); } @Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚 public ItimDaoImpl getItemDaoImpl() { throw new RuntimeException("注释"); }
- 3、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
- 4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。
上面的例子中,其实正是 元素的出现 开启 了事务行为。 - 5、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,
但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。
事务操作(xml声明式事务管理)
- 1.在Spring配置文件中进行配置
- (1)第一步,配置事务管理器
<!--1.创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"></property> </bean>
<!--这里一定要切记,使用xml进行事务管理的时候,bean的id值一定要是transactionManager,否则就会报错-->
- (2)第二步,配置通知
<!--2.配置通知--> <tx:advice id="txadvice"> <!--配置事务参数--> <tx:attributes> <!--指定哪种规则的方法上面添加事务--> <tx:method name="account*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
- (3)第三步,配置切入点和切面
<!--3.配置切入点和切面--> <aop:config> <!--配置切入点--> <aop:pointcut id="pt" expression="execution(* com.Gby.Service.UserService.*(..))"/> <!--配置切面--> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/> </aop:config>
- (1)第一步,配置事务管理器
事务操作(完全注解声明式事务管理)
- 1.创建配置类,使用配置类代替xml配置文件
@Configuration//配置类 @ComponentScan(basePackages = "com.Gby")//组件扫描 @EnableTransactionManagement(proxyTargetClass = false)//开启事务 public class TxConfig { //创建数据库连接池 @Bean public DruidDataSource getDruidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://localhost:3306/book"); druidDataSource.setUsername("root"); druidDataSource.setPassword("gby20010704.."); return druidDataSource; } //创建jdbcTemplate对象 @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource){ //到ioc容器中根据类型找到DataSource JdbcTemplate jdbcTemplate = new JdbcTemplate(); //注入dataSource jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } //创建事务管理器 @Bean public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } }
Spring5框架新功能
- 1.基于Java8,同时兼容jdk9,许多不建议使用的类和方法在代码库里删除
- 2.自带了通用的日志封装
- (1)Spring5已经移除了log4jConfigListener,官方建议使用log4j2
- (2)Spring5框架整合Log4j2
- 引入java包
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.12.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency>
- 第二步创建Log4j2.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!--日志级别一级优先级排序:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL--> <!--Configuration后面的status用于设置Log4j2自身内部信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出--> <configuration status="INFO"> <!--先定义所有的appender--> <appenders> <!--输出日志信息到控制台--> <console name="Console" target="SYSTEM_OUT"> <!--控制日志输出格式--> <Patternlayout pattern="%d{yyyy-MM-dd HH:mm:ss.sss} [%t] %-5level %logger{36} - %msg%n"/> </console> </appenders> <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--> <!--root:用于指定项目的跟日志,如果没有单独指定logger,则会使用root作为默认的日志输出--> <loggers> <root level="info"> <appender-ref ref="Console"/> </root> </loggers> </configuration>
- 引入java包
- 3.Spring5框架核心容器支持@Nullable注解
- (1)@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空
- (2)注解用在方法上面,方法返回值可以为空
@Nullable String getId();
- (3)注解使用在方法参数里面,方法参数可以为空
public <T> void registerBean(@Nullable String beanName)
- (4)注解使用在上面表示属性值可以为空
@Nullable private String book;
- 4.Spring5核心容器支持函数式风格GenericApplicationContext
//函数式风格创建对象,交Spring进行管理 @Test public void testGenericApplicationContext(){ //1.创建GenericApplicationContext对象 GenericApplicationContext context = new GenericApplicationContext(); //2.调用Context的方法对象注册 context.refresh(); context.registerBean("user",User.class,() -> new User()); //3.获取在Spring注册的对象 //User user = context.getBean("com.Gby.pojo.User", User.class); User user = context.getBean("user", User.class); System.out.println(user); }
- 5.Spring5支持整合JUnit5
- (1)整合Junit4
- 第一步引入Spring相关针对测试依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.6.RELEASE</version> <scope>test</scope> </dependency>
- (2)第二步创建测试类,使用注解方式完成
@RunWith(SpringJUnit4ClassRunner.class)//单元测试框架 @ContextConfiguration("classpath:ApplicationContext.xml")//加载配置文件 //这两个注解就相当于ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("AppliCationContext.xml"); public class JTest4 { @Autowired private UserService userService; @Test public void test1(){ userService.accountMoney(); } }
<--可能会出现的错误,版本不一致导致的--> java.lang.NoClassDefFoundError: org/springframework/core/annotation/MergedAnnotations
- 第一步引入Spring相关针对测试依赖
- (2)Spring5整合Junit5
- 第一步引入JUnit5的jar包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.9.RELEASE</version> <scope>test</scope> </dependency>
- 第二步创建测试类,使用注解完成
@ExtendWith(SpringExtension.class) @ContextConfiguration("classpath:ApplicationContext.xml")//加载配置文件 public class JTest5 { @Autowired private UserService userService; @Test public void test(){ } }
- 第一步引入JUnit5的jar包
- (3)使用一个复合注解替代上面两个注解完成整合
@SpringJUnitConfig(locations = "classpath:ApplicationContext.xml") public class JTest5 { @Autowired private UserService userService; @Test public void test(){ userService.accountMoney(); } }
- (1)整合Junit4