Spring框架:IOC、AOP、JdbcTemplate、事务管理,带你一篇速通。
首先告诉大家本篇文章的所有使用的spring依赖版本:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.9</version>
</dependency>
</dependencies>
在项目的resource资源文件夹创建spring的配置文件,然后添加如下代码:
<bean id="book" class="com.dragon.spring5.Book"></bean>
创建对象后,对象内的属性还没有赋值等等,讲诉三种注入属性得到方式:
public class Book {
private String bname;
private String bauthor;
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
public void testbook(){
System.out.println(bname+":"+bauthor);
}
}
然后在spring配置文件中通过property标签进行属性注入,如下:
<bean id="book" class="com.dragon.spring5.Book">
<property name="bname" value="易筋经"></property>
<property name="bauthor" value="达摩老祖"></property>
</bean>
然后测试:
<!--加载spring配置文件创建对象-->
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
<!--反射-->
Book book=context.getBean("book", Book.class);
System.out.println(book);
book.testbook();
public class Book {
private String bname;
private String bauthor;
public Book(String bname, String bauthor) {
this.bname = bname;
this.bauthor = bauthor;
}
public void testbook(){
System.out.println(bname+":"+bauthor);
}
}
然后在spring配置文件中,如下:
<bean id="book" class="com.dragon.spring5.Book">
<constructor-arg name="bname" value="易筋经"></constructor-arg>
<constructor-arg name="bauthor" value="达摩老祖"></constructor-arg>
</bean>
set方法、测试的代码跟上诉一样,不再赘诉。
在spring配置文件中添加p名称空间,和配置代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!--添加p名称空间-->
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">
<bean id="book" class="com.dragon.spring5.Book" p:bname="九阴神功" p:bauthor="无名氏"></bean></beans>
<bean id="book" class="com.dragon.spring5.Book">
<property name="bauthor">
<null/>
</property>
<property name="bname">
<value><![CDATA[<<读者>>]]></value>
</property>
</bean>
spring配置文件:
<bean id="userService" class="com.dragon.spring5.service.UserService">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.dragon.spring5.dao.UserDaoImpl"></bean>
UserService、UserDao、UserDaoImpl、测试类代码:
package com.dragon.spring5.dao;
public interface UserDao {
public void update();
}
=============================================================
package com.dragon.spring5.dao;
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("dao update.......");
}
}
=========================================================
package com.dragon.spring5.service;
import com.dragon.spring5.dao.UserDao;
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("service add........");
userDao.update();
}
}
======================================================
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
UserService userService=context.getBean("userService", UserService.class);
userService.add();
不通过ref属性,而是通过嵌套一个bean标签实现
spring配置文件:
<bean id="emp" class="com.dragon.spring5.bean.Emp">
<property name="enanme" value="lucy"></property>
<property name="gender" value="女"></property>
<property name="dept">
<bean id="dept" class="com.dragon.spring5.bean.Dept">
<property name="dname" value="保安部门"></property>
</bean>
</property>
</bean>
Emp、Dept、测试类代码:
package com.dragon.spring5.bean;
public class Emp {
private String enanme;
private String gender;
private Dept dept;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEnanme(String enanme) {
this.enanme = enanme;
}
public void setGender(String gender) {
this.gender = gender;
}
public void add(){
System.out.println(enanme+"::"+gender+"::"+dept);
}
}
===================================================================
package com.dragon.spring5.bean;
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"dname='" + dname + '\'' +
'}';
}
}
==========================================================================
ApplicationContext context1=new ClassPathXmlApplicationContext("bean2.xml");
Emp emp=context1.getBean("emp", Emp.class);
emp.add();
写法一:也就是上面所说的外部bean,通过ref属性来获取外部bean
写法二:
emp类中有ename和dept两个属性,其中dept有dname属性,写法二需要emp提供dept属性的get方法。
<bean id="emp" class="com.dragon.spring5.bean.Emp">
<property name="enanme" value="john"></property>
<property name="gender" value="男"></property>
<!--写法一-->
<property name="dept" ref="dept"></property>
<!--写法二-->
<property name="dept.dname" value="技术部"></property>
</bean>
<bean id="dept" class="com.dragon.spring5.bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
stu类:
package com.dragon.spring5.collectiontype;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Stu {
private String[] courses;
private List<String> list;
private Map<String,String> maps;
private Set<String> sets;
private List<Course> courselist;
public void setCourselist(List<Course> courselist) {
this.courselist = courselist;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void test(){
System.out.println(Arrays.toString(courses));
System.out.println(list);
System.out.println(maps);
System.out.println(sets);
System.out.println(courselist);
}
}
Course类:
package com.dragon.spring5.collectiontype;
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
spring配置文件:
<bean id="stu" class="com.dragon.spring5.collectiontype.Stu">
<property name="courses">
<array>
<value>java课程</value>
<value>数据库课程</value>
</array>
</property>
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<property name="maps">
<map>
<entry key="JAAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
<!--外部bean注入-->
<property name="courselist">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course2" class="com.dragon.spring5.collectiontype.Course">
<property name="cname" value="MyBatis框架"></property>
</bean>
测试:
ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
Stu stu=context.getBean("stu", Stu.class);
stu.test();
集合提取出来注入:
用util标签(注意util标签怎么引入):
Book类:
package com.dragon.spring5.collectiontype;
import java.util.List;
public class Book {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public void test(){
System.out.println(list);
}
}
<?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:p="http://www.springframework.org/schema/p"
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">
<util:list id="booklist">
<value>易筋经</value>
<value>九阳神功</value>
<value>九阴真经</value>
</util:list>
<bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype">
<property name="list" ref="booklist"></property>
</bean>
</beans>
普通bean在配置文件中定义的bean类型就是返回类型。而工厂bean在配置文件定义的bean类型可以和返回类型不一样。
下面的MyBean类中实现FactoryBean接口,重写getObject,getObjectType方法。
这里把getObject重写成返回Course对象的方法。
package com.dragon.spring5.factorybean;
import com.dragon.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;
public class MyBean implements FactoryBean<Course> {
@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 FactoryBean.super.isSingleton();
}
}
spring配置文件:
<bean id="mybean" class="com.dragon.spring5.factorybean.MyBean"></bean>
测试:
注意这里实例化对象不是MyBean类型,是上面getObject方法返回的对象类型。
ApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
Course course=context.getBean("mybean", Course.class);
System.out.println(course);
ApplicationContext context1=new ClassPathXmlApplicationContext("bean4.xml");
Book book1=context1.getBean("book", Book.class);
Book book2=context1.getBean("book", Book.class);
<bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype">
<property name="list" ref="booklist"></property>
</bean>
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
(6)bean 可以使用了(对象获取到了)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
下面提供大家测试需要用的类,方便大家理解:
Orders类:
package com.dragon.spring5.bean;
public class Orders {
private String oname;
public Orders() {
System.out.println("第一步 执行无参数构造创建bean实例");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用set方法设置属性值");
}
public void initMethod(){
System.out.println("第三步 执行初始化方法");
}
public void destoryMethod(){
System.out.println("第五步 bean销毁的方法");
}
}
后置处理器:
package com.dragon.spring5.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.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;
}
}
测试:
package com.dragon.spring5.testDemo;
import com.dragon.spring5.bean.Orders;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test3 {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean6.xml");
Orders orders=context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建beam实例对象");
System.out.println(orders);
context.close();
}
}
spring配置文件:
</bean>
<!-- 后置处理器-->
<bean id="myBeanPost" class="com.dragon.spring5.bean.MyBeanPost"></bean>
bean标签属性autowire两个常用值:
(1)byName:根据属性名称注入,注入值bean的id值和类属性名称一样
(2)byType:根据属性类型注入
spring配置文件:
(Emp类中有dept属性)
<bean id="emp" class="com.dragon.spring5.autowrite.Emp">
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>
正常情况下属性值需要用property标签注入。
而用autowire,可以自动注入
<bean id="emp" class="com.dragon.spring5.autowrite.Emp" autowire="byName"></bean>
<bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>
这里用连接数据库举例:
在resource文件夹内jdbc属性文件(jdbc.properties)
pro.driverClass=com.mysql.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/?(这个根据自己数据库配置)
pro.username=root
pro.password=root
spring配置文件(注意context配置,这里使用的< context:property-placeholder/ >标签引入属性文件,其中classpath就是配置属性文件的全称):
<?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">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${pro.driverClass}"></property>
<property name="url" value="${pro.url}"></property>
<property name="username" value="${pro.username}"></property>
<property name="password" value="${pro.password}"></property>
</bean>
</beans>
spring提供四种创建对象的注解(下面四个注解说的一般使用在哪层是约定俗成的,其实效果都一样,都可以混用):
<context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>
代表扫描com.dragon.spring5_1下的所有文件,找寻有注解的文件,然后创建实例。
(2)创建类并在类上创建对象注解
@Service(value = "userService")
public class UserService {
public void add(){
System.out.println("service add.......");
}
}
测试:
ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");
UserService userService=context.getBean("userService",UserService.class);
System.out.println(userService);
userService.add();
还有两种用法:
设置不扫描的注解
<context:component-scan base-package="com.dragon.spring5_1">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
设置扫描的注解
<context:component-scan base-package="com.dragon.spring5_1" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
package com.dragon.spring5_1.dao;
import org.springframework.stereotype.Repository;
public interface UserDao {
public void add();
}
==================================================
package com.dragon.spring5_1.dao;
import org.springframework.stereotype.Repository;
@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("dao add......");
}
}
=========================================================
package com.dragon.spring5_1.service;
import com.dragon.spring5_1.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service(value = "userService")
public class UserService {
@Value(value = "abc")
private String name;
@Autowired
@Qualifier(value ="userDaoImpl1")
private UserDao userDao;
public void add(){
System.out.println("service add......."+name);
userDao.add();
}
}
spring配置文件:
<?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">
<context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>
</beans>
测试:
ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");
UserService userService=context.getBean("userService",UserService.class);
System.out.println(userService);
userService.add();
上面讲诉后,完全注解开发应该是最简洁的。来个实例看一看。
这时要引入配置类来代替spring配置文件,来实现组件扫描不用xml配置,进而实现完全注解开发。
配置类:
package com.dragon.spring5_1.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration//配置类
@ComponentScan(basePackages = {"com.dragon.spring5_1"})//配置扫描的文件
public class SpringConfig {
}
测试(UserDao、UserDaoImpl、UserService还是上面基于注解属性注入例子的):
package com.dragon.spring5_1.testDemo;
import com.dragon.spring5_1.config.SpringConfig;
import com.dragon.spring5_1.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class test2 {
public static void main(String[] args) {
//注意new的对象变了,变成了AnnotationConfigApplicationContext
ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService=context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
}
用的依赖(包括上篇文章讲诉的IOC依赖):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>net.sourceforge.cglib</groupId>
<artifactId>com.springsource.net.sf.cglib</artifactId>
<version>2.1.3</version>
</dependency>
核心:
package com.dragon.springaop;
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
================================================
package com.dragon.springaop;
public class UserDaoImpl implements UserDao{
@Override
public int add(int a,int b) {
System.out.println("add方法执行了...");
return a+b;
}
@Override
public String update(String id) {
System.out.println("update方法执行了...");
return id;
}
}
JDKProxy类(通过 java.lang.reflect.Proxy类 的 newProxyInstance方法创建代理类):
package com.dragon.springaop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces={UserDao.class};//创建接口实现类代理对象
UserDaoImpl userDao=new UserDaoImpl();
UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao)) ;
int result=dao.add(1,2);
System.out.println("result:"+result);
}
}
class UserDaoProxy implements InvocationHandler{
//创建的是谁的代理对象,把谁传递过来
//有参构造传递
private Object obj;
public UserDaoProxy (Object obj){
this.obj=obj;
}
//参数含义:代理对象、方法、参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前执行...."+ method.getName()+":传递参数...."+ Arrays.toString(args));
Object res=method.invoke(obj,args);
System.out.println("方法之后执行...."+obj);
return res;
}
}
其实JDK动态代理本质就是在原来要增强的方法前面或后面增加一些逻辑处理等,而不修改源代码。从上面运行结果看以看出,add方法执行结果是3,但是在执行add方法执行多一些语句输出,这些就是我们增加的逻辑处理部分。其中method.invoke()就是模拟的原add方法执行,而前后的输出语句是模拟的增强的代码
AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用进行AOP操作。
execution(* com.auguigu.dao.BookDao.add(..))
execution(* com.atguigu.dao.BookDao.*(..))
execution(* com.atguigu.dao.*.* (..))
User:
注解方式创建User对象user
package com.dragon.springaop.anno;
import org.springframework.stereotype.Component;
@Component
public class User {
public void add(){
System.out.println("add....");
}
}
UserProxy类(先忽略@Order注解):
注解方式创建UserProxy对象userProxy
@Aspect定义UserProxy为切面类(即指把通知应用到切入点的类)
package com.dragon.springaop.anno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect//定义切面类
@Order(3)
public class UserProxy {
@Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void before(){
System.out.println("before.....");
}
@AfterReturning(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning....");
}
@After(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void after(){
System.out.println("after....");
}
@AfterThrowing(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing....");
}
@Around(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
System.out.println("环绕之前....");
proceedingJoinPoint.proceed();
System.out.println("环绕之后....");
}
}
spring配置文件:
<?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"
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.dragon.springaop.anno"/>
<!--开启AspectJ生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
测试:
ApplicationContext context=new ClassPathXmlApplicationContext("beanaop1.xml");
User user=context.getBean("user", User.class);
user.add();
可以看出Befoe(前置通知,在add前运行)、AfterRetruning(后置通知或返回通知,在add返回值后运行)、AfterThrowing(异常通知,在add出现异常后,这个没有运行,因为没异常,大家在add内添加 int i=1/0 测试一下,不在演示)、After(最终通知,在add执行完后)、Around(环绕通知,在add前和后)的运行时期。
上面的UserProxy 类中有很多重复的切入点表达式,可以进行公共提取
@Pointcut(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void pointDemo(){
}
//前置通知
@Before(value="pointDemo()")
public void before(){
System.out.println("before....");
}
上面的实例只有UserProxy一个增强类,当有多个增强类时,可以使用@Order(数值)设置优先级执行。(数字越小优先级越高)
在上诉例子中多创建一个PeopleProxy类,设置@Order:
package com.dragon.springaop.anno;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(1)
public class PersionProxy {
@Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void persionBefore(){
System.out.println("persionBefore.....");
}
}
上面的UserProxy类中我设置的是Order(3),所以PeopleProxylei类先运行。
AOPConfig类:
package com.dragon.springaop.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = {"com.dragon.springaop"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}
Book、BookProxy:
package com.dragon.springaop.aopxml;
import org.springframework.stereotype.Component;
@Component
public class Book {
public void buy(){
System.out.println("buy......");
}
}
========================================
package com.dragon.springaop.aopxml;
public class BookProxy {
public void before(){
System.out.println("before....");
}
}
测试:
ApplicationContext context=new AnnotationConfigApplicationContext(AopConfig.class);
Book book=context.getBean("book", Book.class);
book.buy();
Book、BookProxy:
package com.dragon.springaop.aopxml;
import org.springframework.stereotype.Component;
public class Book {
public void buy(){
System.out.println("buy......");
}
}
========================================
package com.dragon.springaop.aopxml;
public class BookProxy {
public void before(){
System.out.println("before....");
}
}
spring配置文件:
<bean id="book" class="com.dragon.springaop.aopxml.Book"></bean>
<bean id="bookProxy" class="com.dragon.springaop.aopxml.BookProxy"></bean>
<!-- 配置aop增强-->
<aop:config>
<!-- 切入点-->
<aop:pointcut id="p" expression="execution(* com.dragon.springaop.aopxml.Book.buy(..))"/>
<!-- 配置切面-->
<aop:aspect ref="bookProxy">
<!-- 增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"></aop:before>
</aop:aspect>
</aop:config>
测试:
ApplicationContext context=new ClassPathXmlApplicationContext("beanaop2.xml");
Book book=context.getBean("book", Book.class);
book.buy();
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>net.sourceforge.cglib</groupId>
<artifactId>com.springsource.net.sf.cglib</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
</dependency>
</dependencies>
</project>
int update(String sql, Object... args);
T queryForObject(String sql,Class<T> requiredType);
T queryForObject(String sql,Class<T> requiredType);
List<T> query(String sql,RowMapper<T> rowMapper,Object... args);
int[] batchUpdate(String sql,List<Object[]> batchArgs);
实体层——Book实体类:
package com.dragon.jdbc.entity;
public class Book {
private String bookId;
private String bookname;
private String bstatus;
public String getBookId() {
return bookId;
}
public String getBookname() {
return bookname;
}
public String getBstatus() {
return bstatus;
}
public void setBookId(String bookId) {
this.bookId = bookId;
}
public void setBookname(String bookname) {
this.bookname = bookname;
}
public void setBstatus(String bstatus) {
this.bstatus = bstatus;
}
@Override
public String toString() {
return "Book{" +
"bookId='" + bookId + '\'' +
", bookname='" + bookname + '\'' +
", bstatus='" + bstatus + '\'' +
'}';
}
}
Dao层——BookDao类:
package com.dragon.jdbc.dao;
import com.dragon.jdbc.entity.Book;
import java.util.List;
public interface BookDao {
public void add(Book book);//添加
public void update(Book book);//修改更新
public void delete(String id);//删除
public int selectCount();//查找数量,返回int类型
public Book findBookInfo(String id);//根据id查找某本书,返回对象
public List<Book> findAllBook();//查找数据库内所有对象,返回集合
public void bathAddBook(List<Object[]> bathArgs);//批量添加
public void bathUpdateBook(List<Object[]> bathArgs);//批量修改
public void bathDeleteBook(List<Object[]> bathArgs);//批量删除
}
BookDao实现类BookDaoImpl:
package com.dragon.jdbc.dao;
import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
@Repository
public class BookDaoImpl implements BookDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Book book) {
String sql="insert into t_book values(?,?,?)";
Object[] args={book.getBookId(),book.getBookname(),book.getBstatus()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);
}
@Override
public void update(Book book) {
String sql="update t_book set bookname=?,bstatus=? where book_id=?";
Object[] args={book.getBookname(),book.getBstatus(),book.getBookId()};
int update=jdbcTemplate.update(sql,args);
System.out.println(update);
}
@Override
public void delete(String id) {
String sql="delete from t_book where book_id=?";
int update=jdbcTemplate.update(sql,id);
System.out.println(update);
}
@Override
public int selectCount() {
String sql="select count(*) from t_book";
Integer count=jdbcTemplate.queryForObject(sql,Integer.class);
return count;
}
@Override
public Book findBookInfo(String id) {
String sql="select * from t_book where book_id=?";
Book book= jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);
return book;
}
@Override
public List<Book> findAllBook() {
String sql="select * from t_book";
List<Book> bookList=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
return bookList;
}
@Override
public void bathAddBook(List<Object[]> bathArgs) {
String sql="insert into t_book values(?,?,?)";
int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);
System.out.println(Arrays.toString(ints));
}
@Override
public void bathUpdateBook(List<Object[]> bathArgs) {
String sql="update t_book set bookname=?,bstatus=? where book_id=?";
int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);
System.out.println(Arrays.toString(ints));
}
@Override
public void bathDeleteBook(List<Object[]> bathArgs) {
String sql="delete from t_book where book_id=?";
int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);
System.out.println(Arrays.toString(ints));
}
}
service层——BookService:
package com.dragon.jdbc.service;
import com.dragon.jdbc.dao.BookDao;
import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
@Autowired
private BookDao bookDao;
public void addBook(Book book){
bookDao.add(book);
}
public void updateBook(Book book){
bookDao.update(book);
}
public void deleteBook(String id){
bookDao.delete(id);
}
public int findCount(){
return bookDao.selectCount();
}
public Book finOne(String id){
return bookDao.findBookInfo(id);
}
public List<Book> findAll(){
return bookDao.findAllBook();
}
public void bathAdd(List<Object[]> bathArgs){
bookDao.bathAddBook(bathArgs);
}
public void bathUpdate(List<Object[]> bathArgs){
bookDao.bathUpdateBook(bathArgs);
}
public void bathDelete(List<Object[]> bathArgs){
bookDao.bathDeleteBook(bathArgs);
}
}
数据库连接配置——Spring配置文件:
<?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">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${pro.driverClass}"></property>
<property name="url" value="${pro.url}"></property>
<property name="username" value="${pro.username}"></property>
<property name="password" value="${pro.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:component-scan base-package="com.dragon.jdbc"></context:component-scan>
</beans>
properties配置文件——jdbc.properties:
需要自行修改数据库名称(我的是user_db)
pro.driverClass=com.mysql.cj.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
pro.username=root
pro.password=root
测试类:
package com.dragon.jdbc.test;
import com.dragon.jdbc.entity.Book;
import com.dragon.jdbc.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
public class test1 {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("bean8.xml");
BookService bookService=context.getBean("bookService",BookService.class);
// Book book=new Book();
// book.setBookId("1");
// book.setBookname("java");
// book.setBstatus("a");
// bookService.addBook(book);
// Book book=new Book();
// book.setBookId("1");
// book.setBookname("javaup");
// book.setBstatus("a");
// bookService.updateBook(book);
// bookService.deleteBook("1");
// System.out.println( bookService.findCount());
// Book book=bookService.finOne("1");
// System.out.println(book);
// System.out.println(bookService.findAll());
// List
// Object[] o1={"3","java","j"};
// Object[] o2={"4","c++","c"};
// Object[] o3={"5","MySql","m"};
// bathArgs.add(o1);
// bathArgs.add(o2);
// bathArgs.add(o3);
// bookService.bathAdd(bathArgs);
// List
// Object[] o1={"java001","j","3"};
// Object[] o2={"c++002","c","4"};
// Object[] o3={"MySql003","m","5"};
// bathArgs.add(o1);
// bathArgs.add(o2);
// bathArgs.add(o3);
// bookService.bathUpdate(bathArgs);
List<Object[]> bathArgs=new ArrayList<>();
Object[] o1={"3"};
Object[] o2={"4"};
bathArgs.add(o1);
bathArgs.add(o2);
bookService.bathDelete(bathArgs);
}
}
Spring定义了7种传播行为:
传播属性 | 描述 |
---|---|
REQUIRED | 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行 |
REQUIRED_NEW | 当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起 |
SUPPORTS | 如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中 |
NOT_SUPPORTED | 当前方法不应该运行在事务中,如果有运行的事务,将它挂起 |
MANDATORY | 当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常 |
NESTED | 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行 |
这里只图解介绍一个,其他类推
事务在一定时间内进行提交,如果不提交会进行回滚,默认值是-1,设置时间以秒为单位进行计算。
读:查询,写:增删改
默认值是false,表示可以增删改查,设置true后只能查询。
设置出现哪些异常进行事务回滚。
设置出现哪些异常不进行事务回滚。
Spring事务管理提供了一个接口,叫做事务管理器,这个接口针对不同的框架提供不同的实现类。
try{
//开启事务
//进行业务操作
userDao.reduceMoney();
//模拟异常
int i=10/0;
userDao.addMoney();
//没出现异常,事务提交
}catch (Exception e){
//异常,事务回滚
}
@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{
@Autowired
private UserDao userDao;
public void accountMoney(){
userDao.reduceMoney();
int i= 1 / 0;
userDao.addMoney();
}
}
就是上述声明式管理的例子,这里补充一下全部代码:
================userDao====================
package com.dragon.shiwu.dao;
public interface UserDao {
public void addMoney();
public void reduceMoney();
}
==============userDaoImpl===================
package com.dragon.shiwu.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@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");
}
}
==============userService============================
package com.dragon.shiwu.service;
import com.dragon.shiwu.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{
@Autowired
private UserDao userDao;
public void accountMoney(){
userDao.reduceMoney();
int i= 1 / 0;
userDao.addMoney();
}
}
============Spring配置文件===========================(注意这里引入了tx命名空间和)
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${pro.driverClass}"></property>
<property name="url" value="${pro.url}"></property>
<property name="username" value="${pro.username}"></property>
<property name="password" value="${pro.password}"></property>
</bean>
<!--创建JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入数据库连接池-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:component-scan base-package="com.dragon.shiwu"></context:component-scan>
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
运行前:
运行后:
Spring配置文件:
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${pro.driverClass}"></property>
<property name="url" value="${pro.url}"></property>
<property name="username" value="${pro.username}"></property>
<property name="password" value="${pro.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启组件扫描-->
<context:component-scan base-package="com.dragon.shiwu"></context:component-scan>
<!--配置事务通知-->
<tx:advice id="txadvice">
<tx:attributes>
<!--配置事务参数-->
<tx:method name="accountMoney" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切入点和切面-->
<aop:config>
<!-- 配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.dragon.shiwu.service.UserService.*(..))"/>
<!-- 配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>
TxConfig类:
package com.dragon.shiwu.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration//配置类
@ComponentScan(basePackages = "com.dragon.shiwu")//组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/user_db");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
return druidDataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
测试类:
package com.dragon.shiwu.test;
import com.dragon.shiwu.config.TxConfig;
import com.dragon.shiwu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class test2 {
public static void main(String[] args) {
ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = context.getBean("userService",UserService.class);
userService.accountMoney();
}
}
以上就是Spring的全部详细讲解。