BeanFactory和ApplicationContext
BeanFactory:IoC容器基本实现,是Spring内部的接口,不提供开发人员进行使用
加载配置文件的时候不会创建对象,在获取对象(使用)的时候采取创建对象
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
加载配置文件的时候就对配置文件中的对象进行创建
Bean管理是指两个操作
(1)Spring创建对象
(2)Spring注入属性
Bean管理操作有两种方式
(1)基于xml配置文件
(2)基于注解
1.基于xml方式创建对象
<bean id="user" class="edu.usts.cs2020.User">bean>
2.基于xml方式注入属性(DI:依赖注入)
第一种注入方式:set方法
第二种注入方式:有参构造器
p名称空间注入(了解):简化xml配置方式
第一步:添加p名称空间在配置文件中
<beans ...
xmlns:p="http://www.springframework.org/schema/p"
...>bean>
第二步:进行属性注入,在bean标签里面进行注入
3.xml注入其他类型的属性
4.xml注入集合属性
1.注入数组类型属性
2.注入List集合类型属性
3.注入Map集合类型属性
(1)创建类,定义数组、List、Map、Set类型属性,生成对应set方法
(2)在Spring配置文件中配置
4.在集合中设置对象类型的值(见bean1.xml)
<bean id="course1" class="collectiontype.Course">
<property name="cname" value="Spring5框架"/>
bean>
<bean id="course2" class="collectiontype.Course">
<property name="cname" value="Mybatis框架"/>
bean>
<property name="courseList">
<list>
<ref bean="course1"/>
<ref bean="course2"/>
list>
property>
5.把集合注入部分提取出来
第一步 创建类,让这个类作为工厂Bean,实现接口FactoryBean
第二步 实现接口里的方法,在实现的方法中定义返回的bean的类型
![img](img/pic03.png)
生命周期
定义:从对象创建到对象销毁的过程
bean生命周期
演示bean生命周期
Order类
配置文件
测试结果
bean的后置处理器
演示添加后置处理器后的效果
根据指定的装配规则(属性名称或者属性类型),Spring会自动将匹配的属性值进行注入
- 演示自动装配的过程
- 根据属性名称自动注入 autowire=“byName”(即by id)
- 根据属性类型自动注入 autowire=“byType”(即by class)
(1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码的方式,在主干功能里面添加新的功能
(3)使用登录的例子说明AOP
(1)有两种情况的动态代理
第一种 有接口的情况,使用JDK动态代理
创建接口实现类的代理对象,增强类的方法
第二种 没有接口的情况,使用CGLIB动态代理
创建子类的代理对象,增强类的方法
(1)创建接口,定义方法
(2)创建接口实现类,实现方法
(3)使用Proxy类创建接口代理对象
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类的代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(
JDKProxy.class.getClassLoader(),
interfaces,
new UserDaoProxy(userDao)
);
int res = dao.add(1, 2);
System.out.println(res);
}
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler{
//1.把创建的代理对象所代理的类传传递过来
//有参构造进行传递
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行..."+method.getName()+":传递的参数..."+ Arrays.toString(args));
Object res = method.invoke(obj, args);
//方法之后
System.out.println("方法之后执行..."+obj);
return res;
}
}
举例1:对usts.cs2020.dao.UserDao类里面的add方法进行增强
execution(* usts.cs2020.dao.UserDao.add(…))
举例2:对usts.cs2020.dao.UserDao类里面的所有方法进行增强
execution(* usts.cs2020.dao.UserDao.*(…))
举例2:对usts.cs2020.dao包里面的所有类,类里面的所有方法进行增强
execution(* usts.cs2020.dao.*.*(…))
//被增强的类
public class User {
public void add(){
System.out.println("add......");
}
}
//增强的类
public class UserProxy {
//前置通知
public void before(){
System.out.println("before......");
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="usts.cs2020.aopanno"/>
beans>
(2)使用注解创建User和UserProxy对象
//被增强的类
@Component
public class User {}
//增强的类
@Component
public class UserProxy {}
(3)在增强类上面添加注解@Aspect
//增强的类
@Component
@Aspect
public class UserProxy{...}
(4)在Spring配置文件中开启生成代理对象
<aop:aspectj-autoproxy/>
//增强的类
@Component
@Aspect
public class UserProxy {
//前置通知
@Before(value = "execution(* usts.cs2020.aopanno.User.add())")
public void before(){
System.out.println("before......");
}
//最终通知
@After(value = "execution(* usts.cs2020.aopanno.User.add())")
public void after(){
System.out.println("after......");
}
//后置通知(返回通知)
@AfterReturning(value = "execution(* usts.cs2020.aopanno.User.add())")
public void afterReturning(){
System.out.println("afterReturning......");
}
//异常通知
@AfterThrowing(value = "execution(* usts.cs2020.aopanno.User.add())")
public void afterThrowing(){
System.out.println("afterThrowing......");
}
//环绕通知
@Around(value = "execution(* usts.cs2020.aopanno.User.add())")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前......");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕之后......");
}
}
//等价于字符串
private final String ee = "execution(* usts.cs2020.aopanno.User.add())";
@Pointcut(value = "execution(* usts.cs2020.aopanno.User.add())")
//相同切入点抽取
public void pointdemo(){
}
//前置通知
@Before(value = ee)
public void before(){
System.out.println("before......");
}
//最终通知
@After(value = "pointdemo()")
public void after(){
System.out.println("after......");
}
(1)在增强类上面添加注解@Order(数字类型),数值类型值越小优先级越高
@Component
@Aspect
@Order(0)
public class PersonProxy {}
@Component
@Aspect
@Order(1)
public class UserProxy {}
//运行结果
/*
PersonProxy.before......
环绕之前......
UserProxy.before......
add......
afterReturning......
after......
环绕之后......
*/
(1)创建配置类,不需要创建xml文件
@Configuration
@ComponentScan(basePackages = {"usts.cs2020"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AOPConfig {
}
(2)测试代码
@Test
public void testAopAnno2(){
//注意使用AnnotationConfigApplicationContext()构造器
ApplicationContext context =
new AnnotationConfigApplicationContext(AOPConfig.class);
User user = context.getBean("user", User.class);
user.add();
}
<bean id="book" class="usts.cs2020.aopxml.Book"/>
<bean id="bookProxy" class="usts.cs2020.aopxml.BookProxy"/>
<aop:config>
<aop:pointcut id="p" expression="execution(* usts.cs2020.aopxml.Book.buy(..))"/>
<aop:aspect ref="bookProxy">
<aop:before method="before" pointcut-ref="p"/>
aop:aspect>
aop:config>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/user_db?serverTimezone=UTC?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
bean>
(3)配置JdbcTemplate对象,注入DataSource
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
(4)创建service类和dao类,在dao注入jdbcTemplate对象
<context:component-scan base-package="usts.cs2020"/>
@Service
public class UserService {
@Autowired
private UserDao userDao;
}
@Repository
public class UserDaoImpl implements UserDao{
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
}
public class User {
private String userId;
private String username;
private String ustatus;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUstatus() {
return ustatus;
}
public void setUstatus(String ustatus) {
this.ustatus = ustatus;
}
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", username='" + username + '\'' +
", ustatus='" + ustatus + '\'' +
'}';
}
}
update(String sql,Object... args)
//第一个参数:sql语句
//第二个参数:可变参数,设置sql语句值
dao类
@Repository
public class UserDaoImpl implements UserDao{
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//实现添加操作
@Override
public void add(User user) {
//1.创建sql语句
String sql = "insert into t_user values(?,?,?)";
//2.调用方法实现
Object[] args = {user.getUserId(), user.getUsername(), user.getUstatus()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}
}
public class TestUser {
@Test
public void testJdbcTemplate(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
UserService service = context.getBean("userService", UserService.class);
User user = new User();
user.setUserId("1");
user.setUsername("root");
user.setUstatus("live");
service.addUser(user);
}
}
(1)修改
//实现修改操作
@Override
public void update(User user) {
String sql = "update t_user set username=?,ustatus=? where user_id=?";
Object[] args = {user.getUsername(),user.getUstatus(),Integer.parseInt(user.getUserId())};
int update = jdbcTemplate.update(sql, args);
System.out.println("成功修改了"+update+"条记录");
}
(2)删除
//实现删除操作
@Override
public void delete(String userId) {
String sql = "delete from t_user where user_id = ?";
int update = jdbcTemplate.update(sql, Integer.parseInt(userId));
System.out.println("成功删除了"+update+"条记录");
}
(1)查询表里面有多少条记录,返回的是某个值
(2)使用JdbcTemplate实现查询返回某个值的代码
//查询表中记录数
@Override
public int selectCount() {
String sql = "select count(*) from t_user";
//queryForObject(sql, Integer.class);第一个参数为sql语句,第二个参数为返回值类型的class
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
(1)场景:查询用户信息
(2)JdbcTemplate实现查询返回对象
queryForObject(String sql,RowMapper
//查询返回对象
@Override
public User findUserInfo(String userId) {
String sql = "select user_id,username,ustatus from t_user where user_id = ?";
//BeanPropertyRowMapper是RowMapper的实现类
User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), userId);
return user;
}
(1)场景:查询图书列表分页
(2)调用JdbcTemplate方法实现查询返回集合
query(String sql,RowMapper
//查询返回对象集合
@Override
public List<User> findAll() {
String sql = "select user_id,username,ustatus from t_user";
List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
return userList;
}
(1)批量操作:操作表里的多条记录
(2)JdbcTemplate实现批量添加操作
batchUpdate(String sql,List
//批量添加
@Override
public void batchAddUser(List<Object[]> batchArgs) {
String sql = "insert into t_user(username,ustatus) values(?,?)";
int[] updateCount = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(updateCount));
}
测试
//批量添加
List<Object[]> batchArgs = new ArrayList<>();
Object[] args1 = new Object[]{"abc","123"};
Object[] args2 = new Object[]{"qwe","987"};
Object[] args3 = new Object[]{"zxc","456"};
batchArgs.add(args1);
batchArgs.add(args2);
batchArgs.add(args3);
service.batchAdd(batchArgs);
(3)JdbcTemplate实现批量修改操作
//批量修改
@Override
public void batchUpdateUser(List<Object[]> batchArgs) {
String sql = "update t_user set username=?,ustatus=? where user_id=?";
int[] batchUpdate = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(batchUpdate));
}
测试
//批量修改
List<Object[]> batchArgs = new ArrayList<>();
//注意参数的顺序对应
Object[] args1 = new Object[]{"fgh","123",5};
Object[] args2 = new Object[]{"rty","987",6};
Object[] args3 = new Object[]{"uyt","456",7};
batchArgs.add(args1);
batchArgs.add(args2);
batchArgs.add(args3);
service.batchUpdate(batchArgs);
(4)JdbcTemplate实现批量删除操作
//批量删除
@Override
public void batchDeleteUser(List<Object[]> batchArgs) {
String sql = "delete from t_user where user_id = ?";
int[] update = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(update);
}
测试
//批量删除
List<Object[]> batchArgs = new ArrayList<>();
Object[] args1 = {5};
Object[] args2 = {6};
Object[] args3 = {7};
batchArgs.add(args1);
batchArgs.add(args2);
batchArgs.add(args3);
service.batchDelete(batchArgs);
图解
(1)在service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource
配置文件
<!--组件扫描-->
<context:component-scan base-package="usts.cs2020"/>
<context:property-placeholder location="jdbc.properties"/>
<!--配置数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClassName}"/>
<property name="url" value="${prop.url}"/>
<property name="username" value="${prop.username}"/>
<property name="password" value="${prop.password}"/>
</bean>
<!--JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>
service
@Service
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
}
dao
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
}
//多钱
@Override
public void addMoney() {
String sql = "update t_account set money = money + ? where username = ?";
jdbcTemplate.update(sql,"Lucy");
}
//少钱
@Override
public void reduceMoney() {
String sql = "update t_account set money = money - ? where username = ?";
jdbcTemplate.update(sql,"Marry");
}
service
@Service
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
//转账的方法
public void accountMoney(){
//Lucy少100
userDao.reduceMoney();
//Marry多100
userDao.addMoney();
}
}
//转账的方法
public void accountMoney(){
//Lucy少100
userDao.reduceMoney();
//模拟异常
int i = 1/0;
//Marry多100
userDao.addMoney();
}
(1)逻辑上如何解决呢?
使用事务进行解决
(2)事务操作过程
public void accountMoney(){
try {
//第一步 开启事务操作
//第二步 进行业务操作
//Lucy少100
userDao.reduceMoney();
//模拟异常
int i = 1/0;
//Marry多100
userDao.addMoney();
//没有发生异常,提交事务
} catch (Exception e) {
//第四步 出现异常,事务回滚
e.printStackTrace();
}
(1)有两种方式:编程式事务管理和声明式事务管理(使用)
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
...
beans>
(2)开启事务的注解
<tx:annotation-driven transaction-manager="transactionManager"/>
@Service
@Transactional
public class UserService {}
当一个事务的方法被另外一个事务的方法调用的时候,这个事务的方法如何进行
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="accountMoney" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="pt" expression="execution(* usts.cs2020.service.UserService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
aop:config>
@Configuration //配置类
@ComponentScan(basePackages = {"usts.cs2020"}) //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
...
}
//创建数据库的连接池
@Bean
public DataSource getDruidDataSource() {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName("com.mysql.cj.jdbc.Driver");
source.setUrl("jdbc:mysql://localhost:3306/user_db?serverTimezone=UTC&useSSL=false&characterEncoding=utf8");
source.setUsername("root");
source.setPassword("12345678");
return source;
}
//创建jdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource source){
//到IoC容器中根据类型找到dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(source);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource source){
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(source);
return manager;
}