spring是jave EE开发的必备技能
降低开发、框架耦合
spring版本到达5.0,spring framework是最基础的配置
使用对象时,由主动new来交给spring进行处理
对象的创建和控制权交给外部,叫做控制反转
spring提供容器,成为IOC容器
在容器中的对象统称为bean
在容器中建立bean与bean之间依赖关系的整个过程称为依赖注入
-
创建maven工程
-
pom文件导入相关依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<!--测试工具包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
- 在resources目录下创建applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
- 创建主要的类
public interface BookMapper {
public void save();
}
public class BookMapperImpl implements BookMapper {
@Override
public void save() {
System.out.println("bookMapper");
}
}
public class BookServiceImpl implements BookService {
private BookMapper bookMapper = new BookMapperImpl();
@Override
public void save() {
System.out.println("bookService1");
bookMapper.save();
}
}
public interface BookService {
public void save();
}
- 配置bean
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl"/>
<bean id="bookService" class="com.ymx.service.impl.BookServiceImpl"/>
- 测试
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取资源
BookService bookService = (BookService) context.getBean("bookService");
bookService.save();
- 测试结果
- 创建主要的类
public class BookMapperImpl implements BookMapper {
@Override
public void save() {
System.out.println("bookMapper");
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
@Override
public void save() {
System.out.println("bookService");
bookMapper.save();
}
}
- 配置bean
<bean id="bookMapper2" class="com.ymx.mapper.impl.BookMapperImpl2"/>
<bean id="bookService2" class="com.ymx.service.impl.BookServiceImpl2">
<property name="bookMapper" ref="bookMapper2" />
</bean>
- 测试
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取资源
BookService bookService = (BookService) context.getBean("bookService2");
bookService.save();
通过set注入
获取ioc容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
获取bean
BookMapper mapper = (BookMapper) context.getBean("mapper");
执行
mapper.save();
<!--
bean标签标识配置bean
id属性表示为名字
class属性表示定义类型-->
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl"/>
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl" name="mapper mapper2 mapper3"/>
通过name属性进行赋值,可以赋值多个,用, ; 和空格都可以分割
- 创建主要的类
public class BookMapperImpl implements BookMapper {
@Override
public void save() {
System.out.println("bookMapper");
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
@Override
public void save() {
System.out.println("bookService");
bookMapper.save();
}
}
- xml文件配置
<!--配置别名,单例模式
name来设置别名,通过空格 逗号和分号进行分割
scope来设置是否为单例模式,默认为singleton来进行设置-->
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl" scope="prototype"/>
<bean id="bookService" class="com.ymx.service.impl.BookServiceImpl" name="impl impl,impl33;i34" scope="singleton">
<property name="bookMapper" ref="bookMapper" />
</bean>
- 测试
// 获取IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取资源
BookService bookService = (BookService) context.getBean("imp3");
bookService.save();
- 结果
spring创建的bean默认为单例模式,简单来说就是创建的对象是否为同一个
上面的别名配置中已经将scope设置完成
- 测试
@Test
public void test03() {
// 获取IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取资源
BookService bookService = (BookService) context.getBean("impl3");
BookService bookService1 = (BookService) context.getBean("bookService3");
BookMapper bookMapper = (BookMapper) context.getBean("bookMapper3");
BookMapper bookMapper1 = (BookMapper) context.getBean("bookMapper3");
bookService.save();
// 单例模式
System.out.println(bookMapper);
System.out.println(bookMapper1);
System.out.println(bookService);
System.out.println(bookService1);
}
- 结果
spring适合创建需要重复使用的对象,可以看到mapper使用非单例模式,两个不同,表现层对象,业务层对象,数据层对象和工具对象适合单例
spring构造默认使用的方法
添加一段无参的构造方法
public class BookMapperImpl implements BookMapper {
private BookMapperImpl(){
System.out.println("无参构造");
}
@Override
public void save() {
System.out.println("bookMapper");
}
}
添加bean
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl"/>
<bean id="bookService" class="com.ymx.service.impl.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
</bean>
然后测试输出
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookMapper mapper = (BookMapper) context.getBean("bookMapper");
mapper.save();
发现会输出构造函数
无需修改xml文件
bean从创建到消亡的完整过程
控制bean的生命周期
- 添加功能
public void init(){
System.out.println("init");
}
public void destory(){
System.out.println("destory");
}
- xml配置
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl" init-method="init" destroy-method="destroy"/>
<bean id="bookService" class="com.ymx.service.impl.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
</bean>
- 测试
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookMapper mapper = (BookMapper) context.getBean("bookMapper");
mapper.save();
context.registerShutdownHook();
registerShutdownHook()方法虚拟机关闭前需要将容器销毁
close将容器暴力关闭
close必须将它放在最后一排,另一个相对自由
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookServiceImpl implements BookService , InitializingBean, DisposableBean {
private BookMapper bookMapper;
@Override
public void save() {
System.out.println("bservice running");
bookMapper.save();
}
@Override
public void destroy() throws Exception {
System.out.println("service destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
通过这种方式不运行该方法也可以执行,和构造方法类似,因为构造方法在创建时就已经运行起来了
- 定义类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
private UserMapper userMapper;
@Override
public void save() {
System.out.println("bservice running");
bookMapper.save();
userMapper.save();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserMapperImpl implements com.ymx.mapper.UserMapper {
private int id;
private String name;
@Override
public void save() {
System.out.println("userMapper" + id + name);
}
}
public class BookMapperImpl implements BookMapper {
@Override
public void save() {
System.out.println("bookMapper");
}
}
- 配置中使用ref属性注入
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl6"/>
<bean id="userMapper" class="com.ymx.mapper.impl.UserMapperImpl6">
<property name="id" value="1"/>
<property name="name" value="cxk"/>
</bean>
<bean id="bookService" class="com.ymx.service.impl.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/>
<property name="userMapper" ref="userMapper"/>
</bean>
配置userMapper使用基本类型
配置bookService使用引用类型
创建类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
private UserMapper userMapper;
private UserMapper userMapper2;
@Override
public void save() {
System.out.println("bservice running");
bookMapper.save();
userMapper.save();
userMapper2.save();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserMapperImpl implements UserMapper {
private int id;
private String name;
@Override
public void save() {
System.out.println("userMapper" + id + name);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserMapperImpl implements UserMapper {
private int id;
private String name;
@Override
public void save() {
System.out.println("userMapper2" + id + name);
}
}
配置bean
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl"/>
<bean id="userMapper" class="com.ymx.mapper.impl.UserMapperImpl">
<!--通过类型注入-->
<constructor-arg type="int" value="2"/>
<constructor-arg type="java.lang.String" value="蔡徐坤"/>
</bean>
<bean id="userMapper2" class="com.ymx.mapper.impl.UserMapperImpl2">
<!--通过位置来解决-->
<constructor-arg index="0" value="3"/>
<constructor-arg index="1" value="鸡哥"/>
</bean>
<bean id="bookService" class="com.ymx.service.impl.BookServiceImpl">
<!--构造器注入的name识别的是形参的值-->
<constructor-arg name="bookMapper" ref="bookMapper"/>
<constructor-arg name="userMapper" ref="userMapper"/>
<constructor-arg name="userMapper2" ref="userMapper"/>
</bean>
type通过类型,name通过有参构造的形参名,index通过位置
创建类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
@Override
public void save() {
System.out.println("bookService");
bookMapper8.save();
}
}
public class BookMapperImpl implements BookMapper {
@Override
public void save() {
System.out.println("bookMapper");
}
}
配置bean
<!--自动装配-->
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl"/>
<bean id="bookService" class="com.ymx.service.impl.BookServiceImpl" autowire="byName"/>
用两种类型一种byType,一种byName,推荐是用byType,如果有两个类型相同的bean只能使用按名字装配,用于引用类型,自动装配优先级低于set注入和构造器注入
只使用简单类型,特殊类型将和之前的类似,通过ref进行引用
创建类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookMapperImpl implements BookMapper {
private int[] array;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
@Override
public void save() {
System.out.println("bookMapper");
}
}
xml配置
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl">
<property name="array">
<array>
<value>100</value>
<value>100</value>
<value>100</value>
</array>
</property>
<property name="list">
<list>
<value>100</value>
<value>100</value>
<value>200</value>
</list>
</property>
<property name="set">
<set>
<value>100</value>
<value>200</value>
<value>100</value>
<value>200</value>
</set>
</property>
<property name="map">
<map>
<entry key="国家" value="中国"></entry>
<entry key="省份" value="河南"></entry>
<entry key="所在市" value="郑州"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="国家">中国</prop>
<prop key="省份">河南</prop>
<prop key="所在市">郑州</prop>
</props>
</property>
</bean>
测试
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookMapper mapper = (BookMapper) context.getBean("bookMapper9");
mapper.save();
System.out.println(mapper.toString());
导入坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
配置xml
<!--配置druid数据源对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="password" value="123456"/>
</bean>
测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) context.getBean("dataSource1");
System.out.println(dataSource);
}
-
开启context命名空间
-
加载properties
<context:property-placeholder location="classpath:*.properties"/>
- 配置jdbc
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/spring_db
- 修改配置
<!--配置druid数据源对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
- 创建类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookMapperImpl implements BookMapper {
private String name;
@Override
public void save() {
System.out.println("bookMapper");
}
}
- bean配置查看
<bean id="bookMapper" class="com.ymx.mapper.impl.BookMapperImpl">
<property name="name" value="${jdbc.username}"/>
</bean>
- 测试
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) context.getBean("dataSource");
BookMapper mapper = (BookMapper) context.getBean("bookMapper");
System.out.println(mapper);
System.out.println(dataSource);
三种方式
-
BookMapper mapper = (BookMapper) context.getBean("bean的名称");
-
BookMapper mapper = context.getBean("bookMapper",类名.class);
-
BookMapper mapper = context.getBean(类名.class);
第三种不能多个相同类型的bean
xml配置
<context:component-scan base-package="com.ymx"/>
创建类
@Component("bookMapper")
public class BookMapperImpl implements BookMapper {
@Override
public void save() {
System.out.println("bookMapper");
}
}
@Component("bookService")
public class BookServiceImpl implements BookService {
private BookMapper bookMapper ;
@Override
public void save() {
System.out.println("bookService");
bookMapper.save();
}
}
@Component因为我是放在一个模块里的使用数字来进行编号,所以必须指定名字
还可以使用三个衍生注解
- @Controller 用于控制层
- @Service 用于业务层
- @Repository 用于持久层
在后面加括号可以指定id
测试
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookMapper mapper = (BookMapper) context.getBean("bookMapper");
System.out.println(mapper);
BookService bookService11 = (BookService) context.getBean("bookService");
System.out.println(bookService);
创建类
@Configuration
@ComponentScan("com.ymx")
public class SpringConfig {
}
删除xml中的注解配置
测试
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
BookMapper mapper = (BookMapper) context.getBean("bookMapper11");
System.out.println(mapper);
BookService bookService11 = (BookService) context.getBean("bookService11");
System.out.println(bookService11);
如果需要添加多个目录,需要使用数组来进行添加
可以改一下以前的代码变成纯注解模式
@Scope来控制是否为单例模式
@Autowired 默认按照类型装配如果需要按照名字,需要配合使用来指定名字
@Autowired
@Qualifier("bookMapper")
@Value 来给一些普通的值
@Bean将这个设置为bean
@PropertySource来导入文件
@Import
新建类
@Configuration
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setName("123456");
return ds;
}
}
如果导入基本类型,需要赋值
@Value("com.mysql.cj.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String username;
@Value("123456")
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;
}
@Bean
public DataSource dataSource(BookMapper bookMapper){
System.out.println(bookMapper);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setName(password);
return ds;
}
基础类型用变量,引用类型用形参
创建mybatis配置类
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setTypeAliasesPackage("com.ymx.pojo");
factoryBean.setDataSource(dataSource);
return factoryBean;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.ymx.mapper");
return msc;
}
}
导入到SpringConfig中
创建实体类,mapper类和service类和service实现类
@Data
public class Account implements Serializable {
private Integer id;
private String name;
private Integer money;
}
public interface AccountMapper {
@Select("select * from spring_db.tbl_account where id = #{id}")
Account selectById(int id);
}
public interface AccountService {
Account findByid(Integer id);
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
public Account findByid(Integer id) {
return accountMapper.selectById(id);
}
}
测试
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService as = context.getBean(AccountService.class);
Account account = as.findByid(2);
System.out.println(account);
}
在不惊动原始设计的基础上进行 功能增强
连接点:程序执行的任意位置,理解为方法的执行
切入点:匹配连接点的式子
通知:在切入点执行的操作
切面:描述通知和切入点的对应关系
通知类:定义通知的类
导包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.22</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.9.1</version>
</dependency>
创建表
public interface BookMapper {
public void save();
public void update();
}
@Repository
public class BookMapperImpl implements BookMapper {
@Override
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("bookMapper");
}
@Override
public void update() {
System.out.println("book update");
}
}
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.ymx.mapper.BookMapper.update())")
private void pt(){
}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
@Configuration
@ComponentScan("com.ymx")
@EnableAspectJAutoProxy
public class SpringConfig {
}
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.ymx.mapper.BookMapper.update())")
private void pt(){
}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
AOP是通过代理来实现的
execution(void com.ymx.mapper.BookMapper.update())
execution(void com.ymx.mapper.impl.BookMapperimpl.update())
*表示单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的通配符出现
execution(public * com.ymx.*.UserService.find*(*))
..:多个连续的任意符号,用于简化包名和参数的书写
execution(public User com..UserService.findById(..))
+:专用匹配子类类型
execution(* *..Service+.*(..))
代码按照标准规范开发
切入点通常描述接口
访问控制修饰符开发采用public
返回值类型对于增删改使用精准类型,查询使用*
包名不适用..,用*做单个包匹配
接口名/类名采用UserService写成*Service来绑定
@Component
@Aspect
public class MyAdvice {
// 将这个方法定义为切入点
@Pointcut("execution(void com.ymx.mapper.BookMapper.update())")
private void pt() {
}
@Before("pt()")
public void before() {
System.out.println("before");
}
@After("pt()")
public void after() {
System.out.println("after");
}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before");
pjp.proceed();
System.out.println("around after");
return 200;
}
@AfterReturning("pt()")
public void afterReturning(){
System.out.println("afterReturning");
}
@AfterThrowing("pt()")
public void afterThrow(){
System.out.println("afterThrow");
}
}
pom文件
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.22</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
java类
public interface AccountService {
// 添加事务
@Transactional
public void transfer(String out,String in,Integer money);
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
public void transfer(String out, String in, Integer money) {
accountMapper.outMoney(out,money);
accountMapper.inMoney(in,money);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
private Integer id;
private String name;
private Integer money;
}
@Repository
public interface AccountMapper {
@Update("update tbl_account set money = money + #{money} where name = #{name}")
void inMoney(@Param("name") String name,@Param("money") Integer money);
@Update("update tbl_account set money = money - #{money} where name = #{name}")
void outMoney(@Param("name") String name,@Param("money") Integer money);
}
@Configuration
@ComponentScan("com.ymx")
@PropertySource("jdbc.properties")
@Import({JDBCConfig.class, MybatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
@Configuration
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;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSource);
return manager;
}
}