提示:以下是本篇文章正文内容,下面案例可供参考
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。
IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。Spring 容器会负责控
制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控
制权发生了反转,这就是 Spring 的 IoC 思想。
简单来说就是把 new对象的权利 让Spring框架进行接管,不需要我们new对象
1.创建Maven项目
2.导入Spring的pom依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
3.在resources目录下创建 applicationContext.xml/application.xml 文件夹
4.在beans里面创建 bean对象 让spring接管你的实体类bean
5.测试:
5.1 创建BeanFactory beanFactory=new XmlBeanFactory(new FileSystemResource("Spring配置文件名称")); beanFactory.getBean(“bean的Id”)
不推荐使用! BeanFactory是ApplicationContext 的一个父接口
5.2 创建 ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“application.xml”);来找到容器
Team team = (Team) applicationContext.getBean("team"); //从容器中通过ID获取对象
推荐使用!
5.2测试
测试结果如下:
Spring会通过反射来获取我们的对象
1. class 指定bean对应类的全路径
2. name name是bean对应对象的一个标识
3. scope 执行bean对象创建模式和生命周期,scope="singleton"和scope="prototype"
singleton: 单例 默认值 当我们的Spring容器被创建时,带有单例属性的bean对象就被创建了,而且容器中只有唯一的一个对象
prototype: 原型(多例) 多例对象什么时候使用什么时候创建,每次使用都会创建一个新的对象
4. lazy-init true/false :懒加载
true:真懒 获取对象的时候才会创建对象
false:不懒 默认值 立即创建对象 不管使用不使用
5. init-method 只需要加载配置文件即可对象初始化方法 方法必须在实体类bean中创建了
6. destroy-method 对象销毁方法 方法必须在实体类bean中创建了,销毁时需要调用 容器.close()方法来完成销毁。
1. 通过配置文件中创建bean创建会调用无参数构造方法
<bean id="team" class="com.mk.study.Team"></bean>
2. 通过配置文件中创建bean后在bean标签中写入
<bean id="team2" class="com.mk.study.Team" scope="prototype">
<constructor-arg name="id" value="111"/>
<constructor-arg name="name" value="张三" />
<constructor-arg name="location" value="xxx"/>
</bean>
3. 工厂方法
public class MyFactory {
public Team t(){
System.out.println("MyFactory --- 实例方法");
return new Team(1111,"1111","1111");
}
public static Team t2(){
System.out.println("MyFactory --- 静态方法");
return new Team(2222,"2222","2222");
}
}
<!-- 静态方法 可以直接通过bean的工厂方法直接调用-->
<bean id="myFactory" class="com.mk.study.MyFactory" factory-method="t2"></bean>
<!-- 实例方法 通过factory-bean拿到对象 在调用factory-method实例方法 -->
<bean id="factory" class="com.mk.study.MyFactory"></bean>
<bean id="instanceTeam" factory-bean="factory" factory-method="t"></bean>
1. 通过set注入 (常用)
<bean class="com.mk.study.dao.TeamDao" id="teamDao"></bean>
<bean id="service" class="com.mk.study.service.TeamService">
<!-- 通过set方法注入实例对象,对象中必须有setter方法,否则无法注入实例对象 -->
<property name="teamDao" ref="teamDao"></property>
</bean>
2. 通过构造方法来完成注入
<bean class="com.mk.study.dao.TeamDao" id="teamDao"></bean>
<bean id="service2" class="com.mk.study.service.TeamService">
<!-- 通过使用有参数构造方法来完成注入 实例对象 -->
<constructor-arg name="teamDao" ref="teamDao"></constructor-arg>
</bean>
3. 自动注入
<bean class="com.mk.study.dao.TeamDao" id="teamDao"></bean>
通过匹配service3中的引用属性和bean注入的对象 类型 匹配上 就会自动注入到service3中
<bean id="service3" class="com.mk.study.service.TeamService" autowire="byType/byName"></bean>
1. @Component(value="自定义id名") 等于把当前对象交给Spring容器进行管理
2. @Component 若不写value值 默认是对象名 首字母小写后面不变
@Component("teamDao") == <bean class="com.mk.study.dao.TeamDao" id="teamDao"></bean>
我们在对象上引入了 @Component()后需要在Spring的XML配置文件中扫描注解标签:
<context:component-scan base-package="扫描的包名"/>
Component的相关注解:
1. @Repository 加在Dao实现类上
2. @Service 加在Service实现类上
3. @Controller 加在Controller实现类上
1. @Value("属性值") 可以放在实体类的属性中,来给属性赋值
注意: 当@Component()交给Spring接管后,刚刚创建对象时,@Value("属性值")是没有生效的,当Spring创建完毕对象后才给对象的属性赋值。
@Value() 是通过setter方法来给属性赋值,setter方法可以省略
2. @Autowired 添加在对象的引用类型(对象属性)中,当我们给引用属性的对象添加了@Component或依赖注入后,我们的Spring容器会管理对象之间的依赖关系,当写入@Autowired给引用对象属性中后,Spring容器启动后会查找相同的对象类型自动装配给@Autowired下的引用类型属性。
@Autowired
public TeamDao teamDao;
3. @Autowired与@Qualifier("指定依赖注入的id名") 当我们依赖注入相同的对象时,我们想指定某一个对象,可以在@Qualifier("指定依赖注入的id名")中写入指定对象的id标识
AOP为Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态
代理实现程序功能的统一维护的一种技术。
AOP的作用:不修改源码的情况下,程序运行期间对方法进行功能增强
好处:1、减少代码的重复,提高开发效率,便于维护。
2、专注核心业务的开发。
核心业务和服务性代码混合在一起
开发中:各自做自己擅长的事情,运行的时候将服务性代码织入到核心业务中。
通过spring工厂自动实现将服务性代码以切面的方式加入到核心业务代码中。
1. 什么是代理模式?
代理:自己不做,找人帮你做。
代理模式:在一个原有功能的基础上添加新的功能。
分类:静态代理和动态代理
1. 基于类的静态代理
要求继承被代理的类
缺点: 每次只能代理一个类
public class StaticProxy extends TeamService {
public void add(){
try {
System.out.println("开启事务");
super.add();//核心业务由被代理的对象来完成,其他服务性功能由代理来完成
System.out.println("提交事务");
}catch (Exception e){
System.out.println("事务回滚");
}
}
}
基于接口的静态代理
1. 实现接口 InvocationHandler 实现 invoke()方法
2. 实现
被代理对象的接口 name=(被代理对象的接口)Proxy.newProxyInstance("拿到被代理对象的类加载器", "拿到被代理对象的接口", new InvocationHandler() {
/**
* 该方法在目标类的方法被执行时,会被调用,你在调用被代理类的方法时,会先执行invoke(...)这个方法
* @param proxy 代理对象
* @param method 代理对象的方法
* @param args 代理对象的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//此代码是真正执行的目标方法
Object result = method.invoke("被代理的对象", "被代理对象执行方法需要的参数");
//被代理对象的方法执行完毕后的返回值,没有返回null
return result;
}
})
name.方法();
1. CGLIB动态代理使用于 代理对象没有接口的情况
2.
//目标对象 没有接口
NBAService service=new NBAService();
NBAService service1= (NBAService) Enhancer.create(service.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib动态代理");
//核心业务代码
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("cglib动态代理");
return result;
}
});
service1.add("张三",1);
1. Target(目标对象) 要被增强的对象,一般是业务逻辑类的对象。
2. Proxy(代理)一个类被 AOP 织入增强后,就产生一个结果代理类。
3. Joinpoint(连接点) 类里面哪些方法可以被增强,这些方法称为 连接点
4. Pointcut(切入点) 实际被真正增强的方法,称为切入点
切入点表达式:execution(访问权限 方法返回值 方法声明(参数) 异常类型)
符号 * 0-多个任意字符
符号 .. 用在方法参数中,表示任意个参数;用在包名后,表示当前及其子包路径
符号 + 用在类名后,表示当前及其子类;用在接口后,表示当前接口及其实现类
示例:
execution(* com.mk.study.service.*.*(..))
指定切入点为:定义在 service 包里的任意类的任意方法任意参数。
5. Advice(通知/增强) 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
1. 导入Aspects依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
2. 在我们切入方法的这个类上 声明 @Aspect //代理对象
3. 在切入方法上声明 Advice(通知)的类型 例如:@Before()
4. 在第三步的基础上增加 切入点表达式,告诉Spring这个Before要在那个方法前调用
@Before("execution(* com.mk.study.service..*.*(..))")
5. 在Spring的xml配置文件中 开启 自动代理
<aop:aspectj-autoproxy proxy-target-class="true"/>
1. 前置通知+切入点表达式
@Before("execution(* com.mk.study.service..*.*(..))")
2. 后置通知+ 切入点表达式
@AfterReturning(value = "execution(* com.mk.study.service..*.update(..)))",returning = "result")
result: 必须在通知方法中的形参加上Object result 代表的是 切入点方法的返回参数
3. 异常通知+切入点表达式
@AfterThrowing(value = "execution(* com.mk.study.service..*.update(..)))",throwing = "ex")
ex:必须在通知方法中的形参加上Throwing ex 代表的是 切入点方法报错的异常可以捕获到
@AfterThrowing(value = "execution(* com.mk.study.service..*.update(..)))",throwing = "ex")
public void exception(JoinPoint joinPoint,Throwable ex){
System.out.println("异常通知");
System.out.println("切入点的"+joinPoint.getSignature().getName()+"方法报"+ex.getMessage()+"错");
}
4. 最终通知+切入点表达式 无论是否出现异常都会被调用
@After("execution(* com.mk.study.service..*.update(..)))")
5. 环绕通知+切入点表达式
@Around("execution(* com.mk.study.service..*.update(..)))")
public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前");
//切入点方法
Object proceed = joinPoint.proceed();
System.out.println("环绕通知后");
return proceed;
}
<!-- XML 切入点表达式-->
<aop:config>
<!-- ref 引用切面类-->
<aop:aspect ref="myAspect2">
<!-- 通知-->
<aop:before method="before" pointcut="execution(* com.mk.study.aop.MyAspect2.*(..))"></aop:before>
</aop:aspect>
</aop:config>
1. 导入 spring-jdbc mysql c3p0 依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
2.
ComboPooledDataSource c3p0=new ComboPooledDataSource();
c3p0.setDriverClass("com.mysql.cj.jdbc.Driver");
c3p0.setJdbcUrl("jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC&characterEncoding=UTF8&useUnicode=true&useSSL=false");
c3p0.setUser("root");
c3p0.setPassword("密码");
JdbcTemplate jdbcTemplate = new JdbcTemplate(c3p0);
String sql="insert into team() values(2,1)";
int update = jdbcTemplate.update(sql);
System.out.println(update);
1. 配置XML
<!-- 数据源-->
<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC&characterEncoding=UTF8&useUnicode=true&useSSL=false"/>
<property name="user" value="root"/>
<property name="password" value="密码"/>
</bean>
<!-- 把数据源 交给 jdbcTemplate模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="c3p0"/>
</bean>
<!-- 我们的Dao层继承了Spring提供的JdbcDaoSupport类,里面包含了jdbcTemplate,我们只需要把带有数据源的jdbcTemplate交给我们的Dao层即可-->
<bean id="teamDao" class="com.mk.study.dao.TeamDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
2. Dao层
public class TeamDao extends JdbcDaoSupport {
public int insert(Team team){
return this.getJdbcTemplate().update("insert into team values(?,?)",team.getId(),team.getName());
}
}
3. 测试
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("application.xml");
TeamDao teamDao = (TeamDao) applicationContext.getBean("teamDao");
System.out.println(teamDao.insert(new Team(3, "张三")));
}
1. 增加 / 批量增加
public int insert(Team team){
return this.getJdbcTemplate().update("insert into team values(?,?)",team.getId(),team.getName());
}
public int[] batchInsert(){
List<Object[]> arg=new ArrayList();
arg.add(new Object[]{值1,"值2"});
arg.add(new Object[]{值1,"值2"});
arg.add(new Object[]{值1,"值2"});
return this.getJdbcTemplate().batchUpdate("insert into team values(?,?)",arg);
}
2. 删除
public int insert(int id){
return this.getJdbcTemplate().update(sql删除语句,id);
}
3. 更新
public int insert(Team team){
return this.getJdbcTemplate().update(sql更新语句,team.参数);
}
4. 查询
//单值查找 方法1
public Team findById(int id){
// Spring 2.5 提供了一个便利的RowMapper实现-----BeanPropertyRowMapper
// *它可自动将一行数据映射到指定类的实例中 它首先将这个类实例化,然后通过名称匹配的方式,映射到属性中去。
BeanPropertyRowMapper<Team> teamBeanPropertyRowMapper = new BeanPropertyRowMapper<Team>(Team.class);
return this.getJdbcTemplate().queryForObject("select * from team where id=?",teamBeanPropertyRowMapper,id);
}
//单值查找 方法2
public Team findById2(int id){
return this.getJdbcTemplate().queryForObject("select * from team where id=?", new RowMapper<Team>() {
public Team mapRow(ResultSet resultSet, int i) throws SQLException {
Team team = new Team();
team.setId(resultSet.getInt("id"));
team.setName(resultSet.getString("name"));
return team;
}
}, id);
}
5. 查询所有
public List<Team> findAll(){
//它可自动将一行数据映射到指定类的实例中 它首先将这个类实例化,然后通过名称匹配的方式,映射到属性中去。
BeanPropertyRowMapper<Team> teamBeanPropertyRowMapper = new BeanPropertyRowMapper<Team>(Team.class);
return getJdbcTemplate().query("select * from team",teamBeanPropertyRowMapper);
}
//方法2
public List<Team> findAll2(){
return getJdbcTemplate().query("select * from team", new RowMapper<Team>() {
public Team mapRow(ResultSet resultSet, int i) throws SQLException {
Team team = new Team();
team.setId(resultSet.getInt("id"));
team.setName(resultSet.getString("name"));
return team;
}
});
}
6. 获取列数
public int count(){
String sql="select * from team";
//实现了RowCallbackHandler接口,其中简单的实现了对结果集元数据的获取,包括行数、列数、列名、列的类型等信息
RowCountCallbackHandler rowCountCallbackHandler = new RowCountCallbackHandler();
getJdbcTemplate().query(sql,rowCountCallbackHandler);
System.out.println(rowCountCallbackHandler.getRowCount());
System.out.println(rowCountCallbackHandler.getColumnCount());
System.out.println(rowCountCallbackHandler.getColumnNames()[0]);
return rowCountCallbackHandler.getRowCount();
}
//方法2 获取单列计数
public int countCol(){
String sql="select count(1) from team";
return getJdbcTemplate().queryForObject(sql,Integer.class);
}
//方法三 获取多列计数
public Map<String, Object> countCol(){
String sql="select count(1),count(2) from team";
return getJdbcTemplate().queryForMap(sql);
}
1. PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务,如果没有事务则开启事务 (常用 增删改)
2. PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行 (常用 查)
3. PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
配置:
1. 在XML配置文件中写入
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/> //数据源连接数据库的bean对象
</bean>
2. 注解开启事务 <tx:annotation-driven transaction-manager="transactionManager"/>
3. 在方法上加上事务
@Transactional(propagation=Propagation.REQUIRED,rollbackFor = {Exception.class})
// XML方式配置事务
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="c3p0"/> //数据源连接数据库的bean对象
</bean>
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">//连接事务管理器
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.mk.study.service..*.*(..))"/>
<aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pt"></aop:advisor>
</aop:config>
隔离级别 | |
---|---|
ISOLATION_DEFAULT | 这是个 PlatfromTransactionManager 默认的隔离级别, |
ISOLATION_READ_UNCOMMITTED | 它允许另外一个事务可以看 到这个事务未提交的数据。这种隔离级别会产生脏读, 不可重复读和幻像读。 |
ISOLATION_DEFAULT | 这是个 PlatfromTransactionManager 默认的隔离级别, 使用数据库默认的事务隔离级别。 |
ISOLATION_READ_COMMITTED | 保证一个事务修改的数据提交后才能被另外一个事务读 取。另外一个事务不能读取该事务未提交的数据。 |
ISOLATION_SERIALIZABLE | 串行化。不存在并发问题。 |
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/m0_50677223/article/details/119207828
内容来源于网络,如有侵权,请联系作者删除!