pom.xml
添加依赖
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>6.0.9version>
dependency>
dependencies>
spring\src\main\resources\applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.mercurows.dao.impl.BookDaoImpl">bean>
<bean id="bookService" class="com.mercurows.service.impl.BookServiceImpl">bean>
beans>
spring\src\main\java\com\mercurows\dao\BookDao.java
package com.mercurows.dao;
public interface BookDao{
public void save();
}
spring\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
package com.mercurows.dao.impl;
import com.mercurows.dao.BookDao;
public class BookDaoImpl implements BookDao{
public void save() {
System.out.println("Book dao save");
}
}
spring\src\main\java\com\mercurows\service\BookService.java
package com.mercurows.service;
public interface BookService {
public void save();
}
spring\src\main\java\com\mercurows\service\impl\BookServiceImpl.java
package com.mercurows.service.impl;
import com.mercurows.dao.BookDao;
import com.mercurows.dao.impl.BookDaoImpl;
import com.mercurows.service.BookService;
public class BookServiceImpl implements BookService{
private BookDao bookDao = new BookDaoImpl();
public void save(){
System.out.println("Book service save ");
bookDao.save();
}
}
spring\src\main\java\com\mercurows\App2.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mercurows.dao.BookDao;
import com.mercurows.service.BookService;
public class App2
{
public static void main( String[] args )
{
// 3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4. 获取bean
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
对应下面代码中的 注解 5. 5. 5.
对应下面代码中的 注解 6. 6. 6.
且该方法由容器调用
修改文件spring\src\main\java\com\mercurows\service\impl\BookServiceImpl.java
package com.mercurows.service.impl;
import com.mercurows.dao.BookDao;
import com.mercurows.service.BookService;
public class BookServiceImpl implements BookService {
// 5.删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
public void save() {
System.out.println("Book service save ");
bookDao.save();
}
// 6.提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
对应下面代码中的 注解 7. 7. 7.
修改文件spring\src\main\resources\applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao1" class="com.mercurows.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.mercurows.service.impl.BookServiceImpl">
<property name= "bookDao" ref="bookDao1"/>
bean>
beans>
其余的部分与IoC中一致
spring\src\main\java\com\mercurows\App2.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mercurows.dao.BookDao;
import com.mercurows.service.BookService;
public class App2
{
public static void main( String[] args )
{
// 3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4. 获取bean
BookDao bookDao = (BookDao) ctx.getBean("bookDao1");
bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
见上面
spring\src\main\java\com\mercurows\dao\impl\CustomerDaoImpl.java
package com.mercurows.dao.impl;
import com.mercurows.dao.CustmoerDao;
public class CustomerDaoImpl implements CustmoerDao{
public void save() {
System.out.println("customer dao save");
}
}
spring\src\main\java\com\mercurows\dao\CustmoerDao.java
package com.mercurows.dao;
public interface CustmoerDao {
public void save();
}
spring\src\main\java\com\mercurows\factory\CustomerDaoFactory.java
package com.mercurows.factory;
import com.mercurows.dao.CustmoerDao;
import com.mercurows.dao.impl.CustomerDaoImpl;
public class CustomerDaoFactory {
public static CustmoerDao getCustmoerDao() {
return new CustomerDaoImpl();
}
}
spring\src\main\resources\applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="customerDao" class="com.mercurows.factory.CustomerDaoFactory" factory-method="getCustmoerDao"/>
beans>
测试
spring\src\main\java\com\mercurows\AppForInstanceCustomer.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mercurows.dao.CustmoerDao;
public class AppForInstanceCustomer {
public static void main(String[] args) {
// CustmoerDao custmoerDao = CustomerDaoFactory.getCustmoerDao();
// custmoerDao.save();
// 3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4. 获取bean
CustmoerDao customerDao = (CustmoerDao) ctx.getBean("customerDao");
customerDao.save();
}
}
spring\src\main\java\com\mercurows\dao\BrandDao.java
package com.mercurows.dao;
public interface BrandDao{
public void save();
}
spring\src\main\java\com\mercurows\dao\impl\BrandDaoImpl.java
package com.mercurows.dao.impl;
import com.mercurows.dao.BrandDao;
public class BrandDaoImpl implements BrandDao{
public void save() {
System.out.println("Brand dao save");
}
}
spring\src\main\java\com\mercurows\factory\BrandDaoFactory.java
package com.mercurows.factory;
import com.mercurows.dao.BrandDao;
import com.mercurows.dao.impl.BrandDaoImpl;
public class BrandDaoFactory {
public BrandDao getBrandDao() {
return new BrandDaoImpl();
}
}
spring\src\main\resources\applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id = "brandFactory" class="com.mercurows.factory.BrandDaoFactory"/>
<bean id = "brandDao" factory-method="getBrandDao" factory-bean="brandFactory"/>
beans>
测试
spring\src\main\java\com\mercurows\AppForInstanceBrand.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mercurows.dao.BrandDao;
public class AppForInstanceBrand {
public static void main(String[] args) {
// 3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4. 获取bean
BrandDao brandDao = (BrandDao) ctx.getBean("brandDao");
brandDao.save();
}
}
该方法为方法三的改良版
在方法三中的 spring\src\main\resources\applicationContext.xml
配置文件写的不简洁,例如
只为了调用工厂中的方法而生成因为非静态方法所以需要先生成工厂类,
都要指定不同的方法名getBrandDao,没有统一的标准。
具体的,该方法与方法三相比,修改的部分为:
将工厂spring\src\main\java\com\mercurows\factory\BrandDaoFactoryBean.java
删除修改为
package com.mercurows.factory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import com.mercurows.dao.BrandDao;
import com.mercurows.dao.impl.BrandDaoImpl;
// 需要生成什么类就往泛型中放什么类
public class BrandDaoFactoryBean implements FactoryBean<BrandDao>{
@Override
@Nullable
public BrandDao getObject() throws Exception {
// 替代了原来的BrandDaoFactory中的getBrandDao()方法
return new BrandDaoImpl();
}
@Override
@Nullable
public Class<?> getObjectType() {
return BrandDao.class;
}
// 是否为单例
@Override
public boolean isSingleton() {
return true;
}
}
修改了配置文件,spring\src\main\resources\applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id = "brandDao" class="com.mercurows.factory.BrandDaoFactoryBean"/>
beans>
其余的部分对于方法三没有改变。
上面DI入门中成员对象只有一个,即spring\src\main\java\com\mercurows\service\impl\BookServiceImpl.java
中只有private BookDao bookDao
一个成员对象,当需要拥有多个时该如何处理?
下面展示新添private BrandDao brandDao
成员对象。
修改spring\src\main\java\com\mercurows\service\impl\BookServiceImpl.java
:
package com.mercurows.service.impl;
import com.mercurows.dao.BookDao;
import com.mercurows.dao.BrandDao;
import com.mercurows.service.BookService;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private BrandDao brandDao;
public void save() {
System.out.println("Book service save ");
bookDao.save();
brandDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void setBrandDao(BrandDao brandDao) {
this.brandDao = brandDao;
}
}
修改spring\src\main\resources\applicationContext.xml
:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao1" class="com.mercurows.dao.impl.BookDaoImpl"/>
<bean id="brandDao1" class="com.mercurows.dao.impl.BrandDaoImpl"/>
<bean id="bookService" class="com.mercurows.service.impl.BookServiceImpl">
<property name= "bookDao" ref="bookDao1"/>
<property name= "brandDao" ref="brandDao1"/>
bean>
beans>
现在想要往spring\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
中添加两个新的简单类型成员变量。具体操作如下:
修改spring\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
文件:
package com.mercurows.dao.impl;
import com.mercurows.dao.BookDao;
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save " + connectionNum + "," + databaseName);
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
修改spring\src\main\resources\applicationContext.xml
文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao1" class="com.mercurows.dao.impl.BookDaoImpl">
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="100"/>
bean>
<bean id="brandDao" class="com.mercurows.dao.impl.BrandDaoImpl"/>
<bean id="bookService" class="com.mercurows.service.impl.BookServiceImpl">
<property name= "bookDao" ref="bookDao1"/>
<property name= "brandDao" ref="brandDao"/>
bean>
beans>
name=“” 参数为类的集合成员对象名字
修改文件databasesourec\src\main\resources\applicationContext.xml
:
<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*:*.properties" system-properties-mode="NEVER"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="bookDao" class="com.mercurows.dao.impl.BookDaoImpl">
<property name="databaseName" value="${username}"/>
<property name="connectionNum" value="100"/>
bean>
beans>
注意上面property中的value值取自:
databasesourec\src\main\resources\jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/estate
jdbc.username=root
databasesourec\src\main\resources\jdbc2.properties
username=root666
jdbc.password=5508769123
这样上面的值就会注入到databasesourec\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
中对应的成员变量之中去connectionNum
,databaseName
package com.mercurows.dao.impl;
import com.mercurows.dao.BookDao;
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save " + connectionNum + "," + databaseName);
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
其他的项目文件:
databasesourec\src\main\java\com\mercurows\dao\BookDao.java
package com.mercurows.dao;
public interface BookDao{
public void save();
}
databasesourec\src\main\java\com\mercurows\App.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mercurows.dao.BookDao;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
pom.xml
中的依赖项
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>6.0.9version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.13version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
项目结构
spring\src\main\resources\applicationContext.xml
组件扫描
<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.mercurows"/>
beans>
此表明将会查找com.mercurows
目录下的所有使用了@Component("")
注解的类并生成对应bean,例如spring\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
类:
package com.mercurows.dao.impl;
import org.springframework.stereotype.Component;
import com.mercurows.dao.BookDao;
@Component("bookDao")
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save " + connectionNum + "," + databaseName);
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
使用了@Component("bookDao")
,则生成了id为bookDao
的BookDaoImpl的bean
其实如有需要可以更进一步详细到将
改为
测试:
spring\src\main\java\com\mercurows\App2.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mercurows.dao.BookDao;
import com.mercurows.service.impl.BookServiceImpl;
public class App2 {
public static void main(String[] args) {
// 3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4. 获取bean
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
}
}
另外,@Component
默认是什么都不写的。所以我们还可以这么写:
spring\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
package com.mercurows.dao.impl;
import org.springframework.stereotype.Component;
import com.mercurows.dao.BookDao;
@Component
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save " + connectionNum + "," + databaseName);
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
spring\src\main\java\com\mercurows\App2.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mercurows.dao.BookDao;
import com.mercurows.service.impl.BookServiceImpl;
public class App2 {
public static void main(String[] args) {
// 3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 4. 获取bean
//因为没有配置id,所以获取bean只能通过class的方式
BookDao bookDao = (BookDao) ctx.getBean(BookDao.class);
System.out.println(bookDao);
}
}
其他文件
spring\src\main\java\com\mercurows\dao\BookDao.java
package com.mercurows.dao;
public interface BookDao{
public void save();
}
项目结构
使用纯注解开发可以达到不用写配置文件的目的
创建配置spring类
spring_annotation_bean\src\main\java\com\mercurows\config\SpringConfig.java
package com.mercurows.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//@Configuration表明这是配置类
@Configuration
//@ComponentScan代替xml配置文件中的包扫描
// @ComponentScan(com.mercurows)
//或是更为细节的:
@ComponentScan({ "com.mercurows.dao", "com.mercurows.service" })
public class SpringConfig {
}
其他类
spring_annotation_bean\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
package com.mercurows.dao.impl;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.mercurows.dao.BookDao;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
//bean的id
@Component("bookDao")
@Repository
//表示生成的bean为单例模式
@Scope("singleton")
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save " + connectionNum + "," + databaseName);
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
spring_annotation_bean\src\main\java\com\mercurows\dao\BookDao.java
package com.mercurows.dao;
public interface BookDao{
public void save();
}
spring_annotation_bean\src\main\java\com\mercurows\service\impl\BookServiceImpl.java
package com.mercurows.service.impl;
import org.springframework.stereotype.Component;
import com.mercurows.service.BookService;
@Component
public class BookServiceImpl implements BookService {
public void save() {
System.out.println("Book service save ");
}
}
spring_annotation_bean\src\main\java\com\mercurows\service\BookService.java
package com.mercurows.service;
public interface BookService {
public void save();
}
测试类
spring_annotation_bean\src\main\java\com\mercurows\App.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mercurows.config.SpringConfig;
import com.mercurows.dao.BookDao;
import com.mercurows.service.BookService;
public class App
{
public static void main( String[] args )
{
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
项目结构
注解开发依赖注入是在纯注解开发基础上修改而来的,即下面的项目是在上面项目基础上修改的。由于纯注解开发没有了配置文件,因而对于一些引用对象就无法正确注解。
spring_annotation_bean\src\main\java\com\mercurows\service\impl\BookServiceImpl.java
package com.mercurows.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.mercurows.dao.BookDao;
import com.mercurows.service.BookService;
@Service
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao){
this.bookDao = bookDao;
}
public void save() {
System.out.println("Book service save ");
bookDao.save();
}
}
虽然上面有带参的构造函数BookServiceImpl,但是并不会执行,因此成员对象bookDao为null ,需要进行如如下修改:
package com.mercurows.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.mercurows.dao.BookDao;
// import com.mercurows.dao.BrandDao;
import com.mercurows.service.BookService;
@Service
public class BookServiceImpl implements BookService {
// 自动装配,按照BookDao类名来,spring框架中使用具体的实现类作为Bean
@Autowired
private BookDao bookDao;
public void save() {
System.out.println("Book service save ");
bookDao.save();
}
}
填写了自动装载@Autowired
就不用专门为成员引用变量编写setter函数了。
在Spring框架中,通常将接口定义和接口的实现类分开管理。在依赖注入(DI)中,我们通过接口编程实现松耦合的设计,以便在运行时动态地决定使用哪个具体的实现类。
但在实际应用中,当我们使用注解来标记Bean时,Spring会自动扫描并创建Bean的实例。默认情况下,Spring将使用具体的实现类作为Bean,而不是接口本身。这样做的原因是因为Spring无法直接实例化接口,而只能实例化具体的
例如上面项目中,注解@Service打在
BookDaoImpl
类上而非BookDao
类上,但是方法却是:getBean(BookDao.class)
如这个项目中,BookDaoImpl
类实现了BookDao
接口,因此,BookServiceImpl
自动装填成员变量BookDao bookDao
时将会使用BookDaoImpl
来作为bean,这时如果还有一个BookDaoImpl2
类实现了BookDao
接口的话那么BookDaoImpl2
也可以作为bean来实例化类BookServiceImpl
,这时就会出现混乱。报错:
Exception in thread “main” org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘bookServiceImpl’: Unsatisfied dependency expressed through field ‘bookDao’: No qualifying bean of type ‘com.mercurows.dao.BookDao’ available: expected single matching bean but found 2: bookDaoImpl,bookDaoImpl2
解决方法为,修改如下文件:
spring_annotation_bean\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
添加bean的id
package com.mercurows.dao.impl;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.mercurows.dao.BookDao;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
//bean的id
@Component("bookDao")
@Repository
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save " + connectionNum + "," + databaseName);
}
@PostConstruct
public void init() {
System.out.println("init ...");
}
@PreDestroy
public void destroy() {
System.out.println("destroy ...");
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
spring_annotation_bean\src\main\java\com\mercurows\dao\impl\BookDaoImpl2.java
添加bean的id
package com.mercurows.dao.impl;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.mercurows.dao.BookDao;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
//bean的id
@Component("bookDao2")
@Repository
public class BookDaoImpl2 implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save 2 " + connectionNum + "," + databaseName);
}
@PostConstruct
public void init() {
System.out.println("init ...");
}
@PreDestroy
public void destroy() {
System.out.println("destroy ...");
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
spring_annotation_bean\src\main\java\com\mercurows\service\impl\BookServiceImpl.java
装填时指定bean的id
package com.mercurows.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.mercurows.dao.BookDao;
// import com.mercurows.dao.BrandDao;
import com.mercurows.service.BookService;
@Service
public class BookServiceImpl implements BookService {
// 自动装配
@Autowired
@Qualifier("bookDao")
private BookDao bookDao;
public void save() {
System.out.println("Book service save ");
bookDao.save();
}
}
测试类
spring_annotation_bean\src\main\java\com\mercurows\App.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mercurows.config.SpringConfig;
import com.mercurows.service.BookService;
public class App
{
public static void main( String[] args )
{
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookService bookService = ctx.getBean(BookService.class);
bookService.save();
}
}
配置文件
spring_annotation_third_bean_manager\src\main\java\com\mercurows\config\SpringConfig.java
package com.mercurows.config;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration
public class SpringConfig {
// 1.定义一个方法获得要管理的对象
// 2。添加@Bean,表示当前方法的返回值是一个bean
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/estate");
ds.setUsername("root");
ds.setPassword("5508769123");
return ds;
}
}
/*
* The purpose of @Bean is to explicitly declare beans and their dependencies,
* and it is an alternative to using component scanning for bean discovery.
* When using @Bean, Spring will directly invoke the method to create the bean instance,
* and there's no need for component scanning to search for classes marked with specific annotations.
*/
测试
spring_annotation_third_bean_manager\src\main\java\com\mercurows\App.java
package com.mercurows;
import javax.sql.DataSource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mercurows.config.SpringConfig;
public class App
{
public static void main( String[] args )
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
// 根据类型名返回对应的Bean
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource);
}
}
但是若是以后有什么第三方bean都往配置文件SpringConfig.java
中写的话,这个文件就会显得臃肿,因此可以采取将其分离方法,使用@Import导入对应的分离部分。
spring_annotation_third_bean_manager\src\main\java\com\mercurows\config\SpringConfig.java
package com.mercurows.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
// @Import注解只允许写一次,多个数据用数组形式
@Import({JdbcConfig.class})
public class SpringConfig {
}
/*
* If you define a bean using @Bean without specifying any scope,
* it will be a singleton by default,
* and there will be only one instance of that bean throughout the application context.
* The bean will be visible and accessible within the application context,
* but its visibility does not extend beyond it.
* If you need the bean to be visible and accessible across different application contexts
* (e.g., in a multi-module project),
* you can consider using Spring's support for importing configurations from other modules or using Spring's context hierarchy.
*/
spring_annotation_third_bean_manager\src\main\java\com\mercurows\config\JdbcConfig.java
package com.mercurows.config;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import com.alibaba.druid.pool.DruidDataSource;
public class JdbcConfig {
// 1.定义一个方法获得要管理的对象
// 2。添加@Bean,表示当前方法的返回值是一个bean
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/estate");
ds.setUsername("root");
ds.setPassword("5508769123");
return ds;
}
}
/*
* The purpose of @Bean is to explicitly declare beans and their dependencies,
* and it is an alternative to using component scanning for bean discovery.
* When using @Bean, Spring will directly invoke the method to create the bean instance,
* and there's no need for component scanning to search for classes marked with specific annotations.
*/
使用@Value
注解简单类型
spring_annotation_third_bean_manager\src\main\java\com\mercurows\config\JdbcConfig.java
package com.mercurows.config;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import com.alibaba.druid.pool.DruidDataSource;
@PropertySource("jdbc.properties") // 指定属性文件的位置
public class JdbcConfig {
// private static final Logger logger = LoggerFactory.getLogger(JdbcConfig.class);
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
// 1.定义一个方法获得要管理的对象
// 2。添加@Bean,表示当前方法的返回值是一个bean
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
// logger.info("Driver: {}", driver);
return ds;
}
}
这里的@Value
也可以直接写死你需要的数据在里面,这里采用读取配置文件的方式。
spring_annotation_third_bean_manager\src\main\resources\jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/estate
jdbc.username=root
jdbc.password=5508769123
spring_annotation_third_bean_manager\src\main\java\com\mercurows\config\SpringConfig.java
package com.mercurows.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
// @Import注解只允许写一次,多个数据用数组形式
@Import({JdbcConfig.class})
public class SpringConfig {
}
测试
spring_annotation_third_bean_manager\src\main\java\com\mercurows\App.java
package com.mercurows;
import javax.sql.DataSource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mercurows.config.SpringConfig;
public class App
{
public static void main( String[] args )
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
// 根据类型名返回对应的Bean
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource);
}
}
项目结构
在类spring_annotation_third_bean_manager\src\main\java\com\mercurows\config\JdbcConfig.java
中注方法注入BookDao
引用对象
package com.mercurows.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import com.alibaba.druid.pool.DruidDataSource;
import com.mercurows.dao.BookDao;
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
// 1.定义一个方法获得要管理的对象
// 2。添加@Bean,表示当前方法的返回值是一个bean
@Bean
public DataSource dataSource(BookDao bookDao) {
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
添加了@Bean
注解,因此该方法的参数会使用自动装配,即自动寻找标记了实现了BookDao接口的且标记了bean的类。
spring_annotation_third_bean_manager\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
添加@Repository
注解生成bean
package com.mercurows.dao.impl;
import org.springframework.stereotype.Repository;
import com.mercurows.dao.BookDao;
@Repository
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void save() {
System.out.println("Book dao save " + connectionNum + "," + databaseName);
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
}
spring_annotation_third_bean_manager\src\main\java\com\mercurows\dao\BookDao.java
package com.mercurows.dao;
public interface BookDao{
public void save();
}
spring_annotation_third_bean_manager\src\main\java\com\mercurows\config\SpringConfig.java
采用包扫描,扫描自动装配所需的bean的类路径
package com.mercurows.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@PropertySource("classpath:jdbc.properties") // 指定属性文件的位置
//包扫描
@ComponentScan("com.mercurows")
// @Import注解只允许写一次,多个数据用数组形式
@Import({JdbcConfig.class})
public class SpringConfig {
}
测试类
spring_annotation_third_bean_manager\src\main\java\com\mercurows\App.java
package com.mercurows;
import javax.sql.DataSource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mercurows.config.SpringConfig;
public class App
{
public static void main( String[] args )
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
// 根据类型名返回对应的Bean
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource);
}
}
项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wEwoi5Q9-1691158236097)(C:/Users/Mercurows/AppData/Roaming/Typora/typora-user-images/image-20230726183856647.png)]
spriong_mybatis\pom.xml
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.23version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.23version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.20version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.4.8version>
dependency>
<dependency>
<groupId>javax.annotationgroupId>
<artifactId>javax.annotation-apiartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>org.springframework.batchgroupId>
<artifactId>spring-batch-infrastructureartifactId>
<version>4.3.0version>
dependency>
获取数据源
spriong_mybatis\src\main\java\com\mercurows\config\JdbcConfig.java
package com.mercurows.config;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import com.alibaba.druid.pool.DruidDataSource;
public class JdbcConfig {
//private static final Logger logger = LoggerFactory.getLogger(JdbcConfig.class);
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
//logger.info("Driver: {}", driver);
return ds;
}
}
spriong_mybatis\src\main\java\com\mercurows\config\MybatisConfig.java
代替mybatis-config.xml配置文件
package com.mercurows.config;
import javax.sql.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
// 代替mybatis-config.xml配置文件生成SqlSession的功能
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
// 代替mybatis配置文件:mybatis-config.xml 中
// 的语句
ssfb.setTypeAliasesPackage("com.mercurows.domain");
ssfb.setDataSource(dataSource);
return ssfb;
}
//加载sql映射文件 这个项目中是 CityDao.java 文件
// 代替mybatis配置文件:mybatis-config.xml 中包扫描
// 的语句
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.mercurows.dao");
return msc;
}
}
/* 一些注解
通过 setTypeAliasesPackage() 方法设置了类型别名的包路径。
在这个例子中,指定的包路径是 "com.mercurows.domain",
这意味着所有在 com.mercurows.domain 包下的Java类都将被当作类型别名。
假设在这个包下有一个名为 User 的Java类,
设置了类型别名后,你可以在MyBatis的Mapper文件中直接使用 User 来代表这个类,
而不需要使用完整的包名路径,比如不再需要写成 com.mercurows.domain.User。
这样做的好处是在Mapper文件中可以更加简洁地引用Java类,
尤其是在涉及多个Java类的情况下,可以减少冗余的代码。
同时,如果你在Mapper文件中引用了某个Java类作为结果集的返回类型或参数类型,
MyBatis会自动将其与数据库中的记录进行映射。
*/
/*
是在XML配置文件中使用的代码,用于通过XML配置方式设置MyBatis的类型别名。
它也是告诉MyBatis去扫描指定包下的Java类,并将这些类设置为类型别名。
*/
spriong_mybatis\src\main\java\com\mercurows\config\SpringConfig.java
package com.mercurows.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
@Configuration
//包扫描,对应bean的创建识别
@ComponentScan("com.mercurows")
// 导入JdbcConfig.java文件需要读取的数据库信息文件(jdbc.properties)位置
// classpath,表示该项目下的所有class文件均为读取目标
@PropertySource("classpath:jdbc.properties")
@Import({ JdbcConfig.class, MybatisConfig.class })
public class SpringConfig {
}
spriong_mybatis\src\main\resources\jdbc.propertiesn
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/estate
jdbc.username=root
jdbc.password=5508769123
spriong_mybatis\src\main\java\com\mercurows\dao\CityDao.java
package com.mercurows.dao;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.mercurows.domain.City;
// 使用MyBatis的注解方式来定义SQL语句
public interface CityDao {
@Insert("insert into city(name, prov_id) calue(#{name},#{prov_id})")
void save(City city);
@Delete("delete from city where id = #{id}")
void delete(Integer id);
@Update("update city set name = #{name},prov_id = #{prov_id} where id = #{id}")
void update(City city);
@Select("select * from city")
List<City> findAll();
@Select("select * from city where id = #{id}")
City findById(Integer id);
}
spriong_mybatis\src\main\java\com\mercurows\domain\City.java
package com.mercurows.domain;
public class City {
private Integer id;
private String name;
private Integer prov_id;
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setProv_id(Integer prov_id) {
this.prov_id = prov_id;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public Integer getProv_id() {
return prov_id;
}
@Override
public String toString() {
return "Account [id=" + id + ", name=" + name + ", prov_id=" + prov_id + "]";
}
}
spriong_mybatis\src\main\java\com\mercurows\service\CitySrvice.java
package com.mercurows.service;
import java.util.List;
import com.mercurows.domain.City;
public interface CitySrvice {
public void save(City city);
public void update(City city);
public void delete(Integer id);
public City findById(Integer id);
public List<City> findAll();
}
spriong_mybatis\src\main\java\com\mercurows\service\impl\CityServiceImpl.java
package com.mercurows.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mercurows.dao.CityDao;
import com.mercurows.domain.City;
import com.mercurows.service.CitySrvice;
@Service
public class CityServiceImpl implements CitySrvice{
@Autowired
private CityDao cityDao;
@Override
public void save(City city) {
cityDao.save(city);
}
@Override
public void update(City city) {
cityDao.update(city);
}
@Override
public void delete(Integer id) {
cityDao.delete(id);
}
@Override
public City findById(Integer id) {
return cityDao.findById(id);
}
@Override
public List<City> findAll() {
return cityDao.findAll();
}
}
spriong_mybatis\src\main\java\com\mercurows\App.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mercurows.config.SpringConfig;
import com.mercurows.domain.City;
import com.mercurows.service.impl.CityServiceImpl;
public class App
{
public static void main( String[] args )
{
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
CityServiceImpl cityService = ctx.getBean(CityServiceImpl.class);
City city = cityService.findById(80000);
System.out.println(city);
}
}
pom.xml
依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.23version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
spring_aop\src\main\java\com\mercurows\dao\BookDao.java
package com.mercurows.dao;
public interface BookDao {
public void save();
public void update();
}
spring_aop\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
package com.mercurows.dao.impl;
import org.springframework.stereotype.Repository;
import com.mercurows.dao.BookDao;
@Repository
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("book dao save");
}
@Override
public void update(){
System.out.println("book dao update");
}
}
如何在在不修改上面代码的情况下可以让 public void update()
方法也能执行System.out.println(System.currentTimeMillis());
语句呢?使用AOP可以解决。
AOP切面配置
spring_aop\src\main\java\com\mercurows\apo\MyAdvice.java
package com.mercurows.apo;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
// 使该类成为bean而受spring控制
@Component
// 告诉spring 扫描到该类时将其当成aop处理
@Aspect
public class MyAdvice {
// 设置切入点-方法:
// 1.使用接口形式
// 2.使用实现类形式:@Pointcut("execution(void com.mercurows.dao.BookDaoImpl.update())")
@Pointcut("execution(void com.mercurows.dao.BookDao.update())")
// 设置空壳的私有方法作为切入点
private void pt(){}
// 声明在上面的切入点执行之前执行该函数
@Before("pt()")
public void method() {
System.out.println(System.currentTimeMillis());
}
}
测试
spring_aop\src\main\java\com\mercurows\App.java
package com.mercurows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mercurows.config.SpringConfig;
import com.mercurows.dao.BookDao;
public class App
{
public static void main( String[] args )
{
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
// bookDao.save();
bookDao.update();
}
}
输出:
1690649016097
book dao update
可以看出,可以让 public void update()
方法也能执行System.out.println(System.currentTimeMillis());
语句
spring_aop\src\main\java\com\mercurows\config\SpringConfig.java
package com.mercurows.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.mercurows")
// 告诉spring该项目中有使用aop开发的东西
// 与 MyAdvice.java 中的@Aspect配套
@EnableAspectJAutoProxy
public class SpringConfig {
}
项目结构
spring_aop\src\main\java\com\mercurows\dao\impl\BookDaoImpl.java
package com.mercurows.dao.impl;
import org.springframework.stereotype.Repository;
import com.mercurows.dao.BookDao;
@Repository
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("book dao save is running");
}
@Override
public void update(){
System.out.println("book dao update is running");
}
@Override
public int select() {
System.out.println("book dao select is running");
return 100;
}
}
spring_aop\src\main\java\com\mercurows\dao\BookDao.java
package com.mercurows.dao;
public interface BookDao {
public void save();
public void update();
public int select();
}
spring_aop\src\main\java\com\mercurows\apo\MyAdvice.java
package com.mercurows.apo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
// 使该类成为bean而受spring控制
@Component
// 告诉spring 扫描到该类时将其当成aop处理
@Aspect
public class MyAdvice {
// 设置切入点-方法:
// 1.使用接口形式
// 2.使用实现类形式:@Pointcut("execution(void com.mercurows.dao.BookDaoImpl.update())")
@Pointcut("execution(void com.mercurows.dao.BookDao.update())")
// 设置空壳的私有方法作为切入点
private void pt() {
}
@Pointcut("execution(int com.mercurows.dao.BookDao.select())")
private void pt2(){}
// 声明在上面的切入点执行之前执行该函数
@Before("pt()")
public void before() {
System.out.println("before advice..");
}
// 声明在在上面的切入点执行之前执行该函数
@After("pt()")
public void after() {
System.out.println("after advice..");
}
// 声明在在上面的切入点执行前后执行该函数
@Around("pt2()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice..");
// 表示对原始操作的调用
// 环绕通知,可以接受原方法的返回值,最后再将其返回
Integer ret = (Integer)pjp.proceed();
System.out.println("around after advice");
return ret;
}
}
spring_aop_advice_data\src\main\java\com\mercurows\dao\impl\BookDaoImlpl.java
package com.mercurows.dao.impl;
import org.springframework.stereotype.Repository;
import com.mercurows.dao.BookDao;
@Repository
public class BookDaoImlpl implements BookDao{
@Override
public String findName(int id,String name) {
System.out.println("id:" + id + "name:" + name);
// if (true)
// throw new NullPointerException();
return "itcast";
}
}
spring_aop_advice_data\src\main\java\com\mercurows\apo\MyAdvic.java
package com.mercurows.apo;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
// 使该类成为bean而受spring控制
@Component
// 告诉spring 扫描到该类时将其当成aop处理
@Aspect
public class MyAdvic {
// 切入表达式使用了通配符"*",表示匹配任何返回类
// ".."表示该方法可以接受任意数量的参数
@Pointcut("execution(* com.mercurows.dao.BookDao.findName(..))")
private void pt() {
}
@Before("pt()")
public void before(JoinPoint jp) {
// 获取原方法的参数
Object[] ars = jp.getArgs();
System.out.println(Arrays.toString(ars));
System.out.println("before advice");
}
@After("pt()")
public void after(JoinPoint jp) {
// 获取原方法的参数
Object[] ars = jp.getArgs();
System.out.println(Arrays.toString(ars));
System.out.println("aftr advice");
}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp){
// 获取原方法的参数
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args));
// 修改原方法的参数
args[0] = 666;
// 返回被修改过后的参数到原方法中
Object ret = null;
try {
ret = pjp.proceed(args);
} catch (Throwable e) {
e.printStackTrace();
}
return ret;
}
// 告诉知,如果该方法有返回值
// 则其为ret,对应afterReturning中的形参
// 注意:如果原方法是带参数的,则注解书写顺序有要求必须JoinPoint在前如:
// public void afterReturning(JoinPoint jp,Object ret)
@AfterReturning(value = "pt()" , returning = "ret")
public void afterReturning(Object ret) {
System.out.println("afterReturning advice " + ret);
}
// 给个形参来接受异常对象
@AfterThrowing(value = "pt()" , throwing = "t")
public void afterThrowing(Throwable t) {
System.out.println("afterThrowing advice " + t);
}
}
spring_affairs\src\main\java\com\mercurows\config\JdbcConfig.java
package com.mercurows.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
// 2. 设置事务管理器
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
return transactionManager;
}
}
spring_affairs\src\main\java\com\mercurows\config\MybatisConfig.java
package com.mercurows.config;
import javax.sql.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.mercurows.domain");
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.mercurows.dao");
return msc;
}
}
spring_affairs\src\main\java\com\mercurows\config\SpringConfig.java
package com.mercurows.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan({"com.mercurows.service" })
@PropertySource("classpath:jdbc.properties")
@Import({ JdbcConfig.class, MybatisConfig.class })
// 3.开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}
spring_affairs\src\main\java\com\mercurows\dao\AccountDao.java
package com.mercurows.dao;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
public interface AccountDao {
@Update("update account set money = money + #{money} where name = #{name}")
void inMoney(@Param("name") String name, @Param("money") Double money);
@Update("update account set money = money - #{money} where name= #{name}")
void outMoney(@Param("name") String name, @Param("money") Double mmoney);
}
spring_affairs\src\main\java\com\mercurows\domain\Acount.java
package com.mercurows.domain;
public class Acount {
private int id;
private String name;
private Double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Acount [id=" + id + ", name=" + name + ", money=" + money + "]";
}
}
spring_affairs\src\main\java\com\mercurows\service\impl\AccountServiceImpl.java
package com.mercurows.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mercurows.dao.AccountDao;
import com.mercurows.service.AccountService;
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Override
public void transfer(String out, String in, double money) {
// System.out.println("-----------------AccountDao is : "+accountDao);
accountDao.outMoney(out, money);
//人为制造异常
int i = 1/0;
accountDao.inMoney(in, money);
}
}
spring_affairs\src\main\java\com\mercurows\service\AccountService.java
package com.mercurows.service;
import org.springframework.transaction.annotation.Transactional;
public interface AccountService {
/*
* 转账操作
* @param out 传出方
* @param in 转入方
* @param money 金额
*/
// 1.在业务层接口添加spring事务管理
@Transactional
public void transfer(String out, String in, double money);
}
test类
spring_affairs\src\test\java\com\mercurows\AccountServiceTest.java
package com.mercurows;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mercurows.config.SpringConfig;
import com.mercurows.service.AccountService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest
{
@Autowired
private AccountService accountService;
@Test
public void testTransfer() throws IOException {
accountService.transfer("小明", "小黄", 100D);
}
}
开启了事务管理之后,AccountServiceImpl的transfer方法中的accountDao.outMoney()
与
accountDao.inMoney()
方法就同成功同失败了,即要么同时更新数据库要么同时有一个方法异常就同时回滚事务。
事务管理只比前面的普通项目多了代码注解里的三步骤:
// 1.在业务层接口添加spring事务管理
// 2. 设置事务管理器
// 3.开启注解式事务驱动
碎碎念: 这里有个接口AccountDao
其并没有添加注解@Component也没有具体的添加了@Component的实现类,但是在AccountServiceImpl
类中却对成员AccountDao
使用了@Autowired。
这是因为: 在MybatisConfig.java
类中使用了包扫描,将com.mercurows.dao下的所有接口都注册成了 Mapper接口。这些接口都会被 MyBatis 用于创建 Mapper 接口的代理对象,那么 Spring 将会创建相应的 Mapper 代理对象,可以通过 @Autowired
进行自动装配。
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.mercurows.dao");
项目结构
新添类与接口:
spring_affairs\src\main\java\com\mercurows\dao\LogDao.java
package com.mercurows.dao;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
public interface LogDao {
@Insert("insert into log(info,createDate) values(#{info},now()) ")
void log(@Param("info") String info);
}
spring_affairs\src\main\java\com\mercurows\service\LogService.java
package com.mercurows.service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public interface LogService {
// 开启一个船新的事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
void log(String out, String in, Double money);
}
spring_affairs\src\main\java\com\mercurows\service\impl\LogServiceImpl.java
package com.mercurows.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mercurows.dao.LogDao;
import com.mercurows.service.LogService;
@Service
public class LogServiceImpl implements LogService{
@Autowired
private LogDao logDao;
@Override
public void log(String out, String in, Double money) {
logDao.log("转账操作由" + out + "到" + in + "金额 :" + money);
}
}
spring_affairs\src\main\java\com\mercurows\service\impl\AccountServiceImpl.java
package com.mercurows.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mercurows.dao.AccountDao;
import com.mercurows.service.AccountService;
import com.mercurows.service.LogService;
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Autowired
private LogService logService;
@Override
public void transfer(String out, String in, double money) {
try {
accountDao.outMoney(out, money);
int i = 1 / 0;
accountDao.inMoney(in, money);
}
finally {
logService.log(out, in, money);
}
}
}
需要特别注意上面spring_affairs\src\main\java\com\mercurows\service\LogService.java
中的:@Transactional(propagation = Propagation.REQUIRES_NEW)
指定了propagation = Propagation.REQUIRES_NEW
即开启了新的事务
注解的一种配置方式。它指定了方法的事务传播行为为
REQUIRES_NEW
,意味着每次调用该方法都会创建一个新的独立事务,无论当前是否已经存在其他事务。
- 当调用一个标记为
@Transactional(propagation = Propagation.REQUIRES_NEW)
的方法时,Spring 将会创建一个新的事务,并让该方法在这个新事务中运行。- 如果当前存在其他事务(外部事务),调用这个方法将导致外部事务挂起,该方法在自己的独立事务中运行。
- 该方法执行完毕后,如果没有发生异常,它会提交自己的事务。提交的含义是将事务的修改持久化到数据库。
- 如果该方法执行过程中发生异常,则会回滚该方法的事务,即撤销事务执行过程中对数据库的修改。
- 外部事务不会受到内部事务(即被
REQUIRES_NEW
标记的方法)的提交或回滚影响,内外事务是完全独立的。
如果只写@Transactional
的话默认为REQUIRED
:
如果当前存在事务,则加入到当前事务中;如果当前没有事务,则创建一个新事务。
即transfer方法里面的三个事务是一起的。因此三个方法之能同时成功同时失败,不符合预期。
不过我一开的想法是将log()方法做成普通方法而不是事务,这样也能实现该目的。。
进行修改:
spring_affairs\src\main\java\com\mercurows\service\LogService.java
该接口不使用事务,当成普通的方法。
package com.mercurows.service;
public interface LogService {
void log(String out, String in, Double money);
}
spring_affairs\src\main\java\com\mercurows\service\impl\AccountServiceImpl.java
package com.mercurows.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mercurows.dao.AccountDao;
import com.mercurows.service.AccountService;
import com.mercurows.service.LogService;
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Autowired
private LogService logService;
@Override
public void transfer(String out, String in, double money) {
try {
accountDao.outMoney(out, money);
int i = 1 / 0;
accountDao.inMoney(in, money);
} catch (Exception e) {
e.printStackTrace();
}
finally {
logService.log(out, in, money);
}
}
}
在一个事务方法中,当某一段代码(无论是否是在
finally
块中)出现异常时,整个事务都会被回滚,包括事务方法内部调用的非事务方法也会回滚。由于异常被捕获并在
catch
块中处理,程序不会继续向上层抛出异常,因此事务不会回滚。