IOC入门案例
导入依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
定义BookDao接口和BookDaoImpl实现类
public interface BookDao { public void save(); } public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } }
定义BookService接口和BookServiceImpl实现类
public interface BookService { public void save(); } public class BookServiceImpl implements BookService { private BookDao bookDao = new BookDaoImpl(); public void save() { System.out.println("book service save ..."); bookDao.save(); } }
定义applicationContext.xml配置文件并配置BookServiceImpl
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- bean标签:表示配置bean id属性:表示给bean起名字 class属性:表示给bean定义类型 --> <bean id="bookService" class="cn.lixuan.service.impl.BookServiceImpl"></bean> </beans>
初始化IOC容器(Spring核心容器/Spring容器),通过容器获取Bean对象
public class App { public static void main(String[] args) { //1.创建IoC容器对象,加载spring核心配置文件 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2 从IOC容器中获取Bean对象(BookService对象) BookService bookService= (BookService)ctx.getBean("bookService"); //3 调用Bean对象(BookService对象)的方法 bookService.save(); } }
DI入门案例
BookServiceImpl中删除使用new的形式创建对象的代码
public class BookServiceImpl implements BookService { private BookDao bookDao; //删除使用new的形式创建对象的代码 public void save() { System.out.println("book service save ..."); bookDao.save(); } }
提供依赖对象对应的setter方法
public class BookServiceImpl implements BookService { private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.save(); } //提供依赖对象对应的setter方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }
在applicationContext.xml中配置service与dao之间的关系
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- bean标签:表示配置bean id属性:表示给bean起名字 class属性:表示给bean定义类型 --> <bean id="bookDao" class="cn.lixuan.dao.impl.BookDaoImpl"/> <bean id="bookService" class="cn.lixuan.service.impl.BookServiceImpl"> <!--配置server与dao的关系 property标签:表示配置当前bean的属性 name属性:表示配置哪一个具体的属性 ref属性:表示参照哪一个bean --> <property name="bookDao" ref="bookDao"/> </bean> </beans>
Bean的配置
别名配置
<bean id="bookService" name="service bookEbi" class="cn.lixuan.service.impl.BookServiceImpl">
作用范围配置
<!-- prototype, singleton等,默认为单例-->
<bean id="bookService" scope="singleton" class="cn.lixuan.service.impl.BookServiceImpl">
Bean的实例化
构造方法方式
BookDaoImpl实现类
public class BookDaoImpl implements BookDao { // 构造方法 public BookDaoImpl() { System.out.println("book dao constructor is running ...."); } public void save() { System.out.println("book dao save ..."); } }
AppForInstanceBook测试类
public void AppForInstanceBook() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); }
静态工厂方式
OrderDao接口和OrderDaoImpl实现类
public interface OrderDao { public void save(); } public class OrderDaoImpl implements OrderDao { public void save() { System.out.println("order dao save ..."); } }
OrderDaoFatory工厂类
//静态工厂创建对象 public class OrderDaoFactory { // static public static OrderDao getOrderDao(){ System.out.println("factory setup...."); return new OrderDaoImpl(); } }
applicationContext.xml配置
<bean id="orderDao" class="cn.lixuan.factory.OrderDaoFactory" factory-method="getOrderDao"/>
AppForInstanceOrder测试类
public void AppForInstanceOrder() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); OrderDao orderDao = (OrderDao) ctx.getBean("orderDao"); orderDao.save(); }
实例工厂方式
UserDaoFactory工厂类
//实例工厂创建对象 public class UserDaoFactory { public UserDao getUserDao(){ return new UserDaoImpl(); } }
applicationContext.xml配置
<bean id="userFactory" class="cn.lixuan.factory.UserDaoFactory"/> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
AppForInstanceUser测试类
public void AppForInstanceUser() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) ctx.getBean("userDao"); userDao.save(); }
Bean的生命周期
方式一 提供生命周期控制方法
public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } //表示bean初始化对应的操作 public void init(){ System.out.println("init..."); } //表示bean销毁前对应的操作 public void destory(){ System.out.println("destory..."); } }
方式二 实现InitializingBean, DisposableBean接口
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean { private BookDao bookDao; public void setBookDao(BookDao bookDao) { System.out.println("set ....."); this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); } public void destroy() throws Exception { System.out.println("service destroy"); } public void afterPropertiesSet() throws Exception { System.out.println("service init"); } }
applicationContext.xml配置
<!--init-method:设置bean初始化生命周期回调函数,此处填写init方法名--> <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,此处填写destory方法名--> <bean id="bookDao" class="cn.lixuan.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
测试类
public void AppForLifeCycle() { //此处需要使用ClassPathXmlApplicationContext,ApplicationContext没有close方法 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器 //ctx.registerShutdownHook(); //关闭容器,执行销毁的方法 ctx.close(); }
依赖注入
依赖注入的两种方式
setter注入, 构造器注入
<bean id="bookDao" class="cn.lixuan.dao.impl.BookDaoImpl"/> <!-- setter引用类型注入 --> <bean id="bookService" class="cn.lixuan.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> <!-- setter简单类型注入 --> <bean id="bookService" class="cn.lixuan.service.impl.BookServiceImpl"> <property name="bookDao" value="20"/> </bean> <!-- 构造方式注入,需提供对应的构造方法 --> <bean id="bookService" class="cn.lixuan.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> </bean>
按类型自动装配
<bean id="bookDao" class="cn.lixuan.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="cn.lixuan.service.impl.BookServiceImpl" autowire="byType"/>
集合注入
注入数组类型数据
<property name="array"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property>
注入List类型数据
<property name="list"> <list> <value>itcast</value> <value>itheima</value> <value>boxuegu</value> <value>chuanzhihui</value> </list> </property>
注入Set类型数据
<property name="set"> <set> <value>itcast</value> <value>itheima</value> <value>boxuegu</value> <value>boxuegu</value> </set> </property>
注入Map类型数据
<property name="map"> <map> <entry key="country" value="china"/> <entry key="province" value="henan"/> <entry key="city" value="kaifeng"/> </map> </property>
注入Properties类型数据
<property name="properties"> <props> <prop key="country">china</prop> <prop key="province">henan</prop> <prop key="city">kaifeng</prop> </props> </property>
第三方资源配置管理
管理Druid连接池
数据库准备
create database if not exists spring_db character set utf8; use spring_db; create table if not exists tbl_account( id int primary key auto_increment, name varchar(20), money double ); insert into tbl_account values(null,'Tom',1000); insert into tbl_account values(null,'Jerry',1000);
添加依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
配置DruidDataSource连接池Bean对象
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean>
在测试类中从IOC容器中获取连接池对象并打印
public void duridTest)() { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource dataSource = (DataSource) ctx.getBean("dataSource"); System.out.println(dataSource); }
管理C3P0连接池
添加c3p0连接池依赖
<dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency>
配置c3p0连接池Bean对象
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/> <property name="user" value="root"/> <property name="password" value="root"/> <property name="maxPoolSize" value="1000"/> </bean>
在测试类中从IOC容器中获取连接池对象并打印
public void c3p0Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource dataSource = (DataSource) ctx.getBean("dataSource"); System.out.println(dataSource); } }
加载properties属性文件
编写jdbc.properties属性文件
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db jdbc.username=root jdbc.password=root
在applicationContext.xml中开启开启context命名空间,加载jdbc.properties属性文件
<?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 "> <!-- 加载多个properties文件 --> <!-- <context:property-placeholder-location="jdbc.properties,msg.properties"/> --> <context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/> <bean class="com.alibaba.druid.pool.DruidDataSource"> <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="cn.lixuan.dao.impl.BookDaoImpl"> <property name="name" value="${username}"/> </bean> </beans>
Spring容器
加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
获取Bean对象
使用bean名称获取(需要自己强制类型转换)
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
使用bean类型获取(如果IOC容器中同类型的Bean对象有多个,此处获取会报错)
BookDao bookDao = ctx.getBean(BookDao.class);
Spring注解开发
@Component注解的三个衍生注解
- @Controller:用于表现层bean定义
- @Service:用于业务层bean定义
- @Repository:用于数据层bean定义
定义配置类代替配置文件
//声明当前类为Spring配置类 @Configuration @ComponentScan("cn.lixuan") //设置bean扫描路径,多个路径书写为字符串数组格式 //@ComponentScan({"cn.lixuan.service","cn.lixuan.dao"}) public class SpringConfig { }
在测试类中加载配置类,获取Bean对象并使用
public void AppForAnnotation() { 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); }
作用范围与生命周期
@Repository
@Scope("singleton")
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor ...");
}
@PostConstruct
public void init(){
System.out.println("book init ...");
}
@PreDestroy
public void destroy(){
System.out.println("book destory ...");
}
}
<!-- JDK9后使用@PostConstruct和@PreDestroy要导入依赖 -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
自动装配
@Service
public class BookServiceImpl implements BookService {
//@Autowired:注入引用类型,自动装配模式,默认按类型装配
@Autowired
//@Qualifier:自动装配bean时按bean名称装配
//@Qualifier("bookDao")
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
使用@Value实现简单类型注入
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
//@Value:注入简单类型(无需提供set方法)
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
// 以上@Value注解中使用${name}从属性文件中读取name值,那么就需要在配置类或者配置文件中加载属性文件
@Configuration
@ComponentScan("cn.lixuan")
//@PropertySource加载properties配置文件
@PropertySource({"classpath:jdbc.properties"}) //{}可以省略不写
public class SpringConfig {
}
注解开发管理第三方Bean
单独定义配置类
public class JdbcConfig { //@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中 @Bean public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/spring_db"); ds.setUsername("root"); ds.setPassword("root"); return ds; } }
将独立的配置类加入核心配置
@Configuration @ComponentScan("cn.lixuan") //@Import:导入配置信息 @Import({JdbcConfig.class}) //@ComponentScan({"cn.lixuan.config","cn.lixuan.service","cn.lixuan.dao"}) //只要cn.lixuan.config包扫到了就行,三个包可以合并写成cn.lixuan public class SpringConfig { }
注解开发为第三方Bean注入资源
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("root")
private String password;
//2.@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
引用类型依赖注入
//Spring会自动从IOC容器中找到BookDao对象赋值给参数bookDao变量,如果没有就会报错。
@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;
}
Spring整合
Spring整合Mybatis
添加依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency>
准备service和dao层基础代码
public interface AccountService { void save(Account account); void delete(Integer id); void update(Account account); List<Account> findAll(); Account findById(Integer id); }
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; public void save(Account account) { accountDao.save(account); } public void update(Account account){ accountDao.update(account); } public void delete(Integer id) { accountDao.delete(id); } public Account findById(Integer id) { return accountDao.findById(id); } public List<Account> findAll() { return accountDao.findAll(); } }
public interface AccountDao { @Insert("insert into tbl_account(name,money)values(#{name},#{money})") void save(Account account); @Delete("delete from tbl_account where id = #{id} ") void delete(Integer id); @Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ") void update(Account account); @Select("select * from tbl_account") List<Account> findAll(); @Select("select * from tbl_account where id = #{id} ") Account findById(Integer id); }
创建JdbcConfig配置DataSource数据源
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false jdbc.username=root jdbc.password=root
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 public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } }
创建MybatisConfig整合mybatis
public class MybatisConfig { //定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象 @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("cn.lixuan.domain"); ssfb.setDataSource(dataSource); return ssfb; } //定义bean,返回MapperScannerConfigurer对象 @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("cn.lixuan.dao"); return msc; } }
创建SpringConfig主配置类进行包扫描和加载其他配置类
@Configuration @ComponentScan("cn.lixuan") //@PropertySource:加载类路径jdbc.properties文件 @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MybatisConfig.class}) public class SpringConfig { }
定义测试类进行测试
public void springMyBatis() { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); AccountService accountService = ctx.getBean(AccountService.class); Account ac = accountService.findById(1); System.out.println(ac); }
Spring整合Junit
导入依赖
<!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--spring整合junit--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.9.RELEASE</version> </dependency>
加载配置文件或者配置类
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {SpringConfig.class}) public class AccountServiceTest { //支持自动装配注入bean @Autowired private AccountService accountService; @Test public void testFindById(){ System.out.println(accountService.findById(1)); } @Test public void testFindAll(){ System.out.println(accountService.findAll()); } }
AOP
导入aop相关坐标
<dependencies> <!--spring核心依赖,会将spring-aop传递进来--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!--切入点表达式依赖,目的是找到切入点方法,也就是找到要增强的方法--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> </dependencies>
定义dao接口与实现类
public interface BookDao { public void save(); public void update(); }
@Repository public class BookDaoImpl implements BookDao { public void save() { System.out.println(System.currentTimeMillis()); System.out.println("book dao save ..."); } public void update(){ System.out.println("book dao update ..."); } }
定义通知类,制作通知方法
//通知类必须配置成Spring管理的bean @Component public class MyAdvice { public void method(){ System.out.println(System.currentTimeMillis()); } }
定义切入点表达式、配置切面(绑定切入点与通知关系)
//通知类必须配置成Spring管理的bean @Component //设置当前类为切面类类 @Aspect public class MyAdvice { //设置切入点,@Pointcut注解要求配置在方法上方 @Pointcut("execution(void cn.lixuan.dao.BookDao.update())") private void pt(){} //设置在切入点pt()的前面运行当前操作(前置通知) @Before("pt()") public void method(){ System.out.println(System.currentTimeMillis()); } }
在配置类中进行Spring注解包扫描和开启AOP功能
@Configuration @ComponentScan("cn.lixuan") //开启注解开发AOP功能 @EnableAspectJAutoProxy public class SpringConfig { }
测试类和运行结果
public void testAOP() { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); BookDao bookDao = ctx.getBean(BookDao.class); bookDao.update(); }
切入点表达式
// * :单个独立的任意符号
// .. : 多个连续的任意符号
// + : 专用于匹配子类类型
execution(void cn.lixuan.dao.BookDao.update())
通知类型
前置通知
后置通知
返回后通知:@AfterReturning
抛出异常后通知:@AfterThrowing
环绕通知:@Around
// 环绕通知方法的返回值建议写成Object类型, 用于将原始对象方法的返回值进行返回 @Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before advice ..."); Object ret = pjp.proceed(); System.out.println("around after advice ..."); return ret; }
AOP案例
测量业务层接口万次执行效率
编写通知类
@Component @Aspect public class ProjectAdvice { //匹配业务层的所有方法 @Pointcut("execution(* cn.lixuan.service.*Service.*(..))") private void servicePt(){} //设置环绕通知,在原始操作的运行前后记录执行时间 @Around("servicePt()") public void runSpeed(ProceedingJoinPoint pjp) throws Throwable { //获取执行的签名对象 Signature signature = pjp.getSignature(); //获取接口/类全限定名 String className = signature.getDeclaringTypeName(); //获取方法名 String methodName = signature.getName(); //记录开始时间 long start = System.currentTimeMillis(); //执行万次操作 for (int i = 0; i < 10000; i++) { pjp.proceed(); } //记录结束时间 long end = System.currentTimeMillis(); //打印执行结果 System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms"); } }
在SpringConfig配置类上开启AOP注解功能
@Configuration @ComponentScan("cn.lixuan") @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MybatisConfig.class}) @EnableAspectJAutoProxy //开启AOP注解功能 public class SpringConfig { }
运行测试类,查看结果
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceTestCase { @Autowired private AccountService accountService; @Test public void testFindById(){ Account account = accountService.findById(2); } @Test public void testFindAll(){ List<Account> list = accountService.findAll(); } }
AOP切入点数据获取
获取参数
@Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { Object[] args = pjp.getArgs(); //获取连接点方法的参数们 System.out.println(Arrays.toString(args)); Object ret = pjp.proceed(); return ret; }
抛出异常后通知可以获取切入点方法中出现的异常信息,使用形参可以接收对应的异常对象
@AfterThrowing(value = "pt()",throwing = "t") public void afterReturning(Throwable t) { //变量名要和returning="t"的属性值一致 System.out.println("afterReturning advice ..."+t); }
@Around("pt()") public Object around(ProceedingJoinPoint pjp) { Object ret = null; //此处需要try...catch处理,catch中捕获到的异常就是连接点方法中抛出的异常 try { ret = pjp.proceed(); } catch (Throwable t) { t.printStackTrace(); } return ret; }
环绕通知中可以手工书写对原始方法的调用,得到的结果即为原始方法的返回值
@Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 手动调用连接点方法,返回值就是连接点方法的返回值 Object ret = pjp.proceed(); return ret; }
百度网盘密码数据兼容处理
service层
public interface ResourcesService { public boolean openURL(String url ,String password); } @Service public class ResourcesServiceImpl implements ResourcesService { @Autowired private ResourcesDao resourcesDao; public boolean openURL(String url, String password) { return resourcesDao.readResources(url,password); } }
dao层
public interface ResourcesDao { boolean readResources(String url, String password); } @Repository public class ResourcesDaoImpl implements ResourcesDao { public boolean readResources(String url, String password) { System.out.println(password.length()); //模拟校验 return password.equals("root"); } }
编写通知类
@Component @Aspect public class DataAdvice { @Pointcut("execution(boolean cn.lixuan.service.*Service.*(*,*))") private void servicePt(){} @Around("DataAdvice.servicePt()") public Object trimStr(ProceedingJoinPoint pjp) throws Throwable { Object[] args = pjp.getArgs(); for (int i = 0; i < args.length; i++) { //判断参数是不是字符串 if(args[i].getClass().equals(String.class)){ args[i] = args[i].toString().trim(); } } Object ret = pjp.proceed(args); return ret; } }
在SpringConfig配置类上开启AOP注解功能
@Configuration @ComponentScan("cn.lixuan") @EnableAspectJAutoProxy public class SpringConfig { }
运行测试类,查看结果
public void testBaidu() { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); ResourcesService resourcesService = ctx.getBean(ResourcesService.class); boolean flag = resourcesService.openURL("http://pan.baidu.com/haha", "root "); System.out.println(flag); }
Spring事物管理
dao层
public interface AccountDao { @Update("update tbl_account set money = money + #{money} where name = #{name}") void inMoney(@Param("name") String name, @Param("money") Double money); @Update("update tbl_account set money = money - #{money} where name = #{name}") void outMoney(@Param("name") String name, @Param("money") Double money); }
service层
public interface AccountService { /** * 转账操作 * @param out 传出方 * @param in 转入方 * @param money 金额 */ //配置当前接口方法具有事务 @Transactional public void transfer(String out,String in ,Double money) ; } @Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; public void transfer(String out,String in ,Double money) { accountDao.outMoney(out,money); int i = 1/0; accountDao.inMoney(in,money); } }
在JdbcConfig中配置事务管理器
//配置事务管理器,mybatis使用的是jdbc事务 @Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager dtm = new DataSourceTransactionManager(); dtm.setDataSource(dataSource); return dtm; }
开启注解式事务驱动
@Configuration @ComponentScan("cn.lixuan") @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MybatisConfig.class}) //开启注解式事务驱动 @EnableTransactionManagement public class SpringConfig { }
运行测试类,查看结果
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceTest { @Autowired private AccountService accountService; @Test public void testTransfer() throws IOException { accountService.transfer("Tom","Jerry",100D); } }
案例:转账业务追加日志
创建日志表
USE spring_db; CREATE TABLE tbl_log( id INT PRIMARY KEY AUTO_INCREMENT, info VARCHAR(255), createDate DATE );
准备环境
public interface LogService { //propagation设置事务属性:传播行为设置为当前操作需要新事务 @Transactional void log(String out, String in, Double money); } @Service public class LogServiceImpl implements LogService { @Autowired private LogDao logDao; public void log(String out,String in,Double money ) { logDao.log("转账操作由"+out+"到"+in+",金额:"+money); } } public interface LogDao { @Insert("insert into tbl_log (info,createDate) values(#{info},now())") void log(String info); }
在AccountServiceImpl中调用logService中添加日志的方法
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private LogService logService; 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); } } }
在LogService的log()方法上设置事务的传播行为
public interface LogService { //propagation设置事务属性:传播行为设置为当前操作需要新事务 @Transactional(propagation = Propagation.REQUIRES_NEW) void log(String out, String in, Double money); }
运行测试类,查看结果
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceTest { @Autowired private AccountService accountService; @Test public void testTransfer() throws IOException { accountService.transfer("Tom","Jerry",50D); } }