目录
1. 作用域,name,id区别,生成对象模式,生成对象时间
1. 作用域,name,id区别,生成对象模式,生成对象时间
<?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">
<!--
4大作用域对象:page,request(请求范围),session(回话范围),application(应用范围)
Spring框架创建对象,一个bean就是一个对象
创建对象一定要使用new关键字吗?错 反射也可以创建对象 newInstance()
创建对象一定要调用构造方法吗? 对-->
<!--Spring框架可以管理对象的生命周期,IOC容器管理对象
bean标签中id和name的区别
id属性:表示对象的唯一标识,整合SpringIOC容器中,ID不能重复,不能以数字开头(合法标识符)
name属性:表示对象的名字,一个对象可以有多个名字
SpringIOC中,生成的对象是单例的SingleTon scope="singleton" 默认的!
多例 scope="prototype" 每次从Spring框架中获取的对象是新new出来的对象
scope="request" web环境,表示每次请求,Spring框架会新new一个对象
scope="session" web环境,表示会话范围内,Spring框架会新new一个对象
scope="globalsession" web环境,表示全局会话范围内,Spring框架会新new一个对象
-->
<bean id="m1" class="com.weng.bean.Man">
<!--赋值,底层掉的set方法-->
<property name="age" value="90"/>
<property name="address" value="wuqiao"/>
<property name="name" value="zhouxingxing"/>
<property name="car" ref="c1"/>
</bean>
<bean id="c1" class="com.weng.bean.Car">
<property name="name" value="falali"/>
</bean>
<bean id="c2" class="com.weng.bean.Car">
<property name="name" value="baoshijie"/>
</bean>
<!--多例 scope="prototype"
lazy-init:懒初始化,表示Spring创建对象的时机
前提:scope="singleton"
Spring中对象默认是,框架一旦加载启动,那么立即创建容器中所有的对象lazy-init="default"或者false
lazy-init="true"表示Spring框架在启动加载的时候没有立即创建对象,而是在使用的时候创建指定对象,节省内存
如果scope="prototype"那么不管lazy-init,都是使用时创建
init-method初始化方法
destory-method销毁对象方法
-->
<bean id="p" class="com.weng.bean.Person" scope="prototype" lazy-init="true"
init-method="init" destroy-method="destory">
<property name="name" value="刘德华"/>
</bean>
</beans>
2.Spring给对象赋值的4种方式
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring给对象赋值的几种方式(对象属性注入方法)-->
<!--方法1:set注入:调用set方法属性赋值,默认调用set方法-->
<bean id="d1" class="com.weng.bean.Dog">
<property name="id" value="1"/>
<property name="name" value="wudi"/>
</bean>
<!--方法2:构造注入:调用构造方法赋值-->
<bean id="d2" class="com.weng.bean.Dog">
<constructor-arg index="0" value="2"/>
<constructor-arg index="1" value="wahd"/>
</bean>
<!--方式3:p命令空间赋值,语法简洁,本质是set注入-->
<bean id="d3" class="com.weng.bean.Dog" p:id="3" p:name="小狗"/>
<!--方式4:SpEl表达式注入-->
<bean id="s4" class="com.weng.bean.Dog">
<property name="id" value="4"/>
<!--引用别的对象的值,d3.name引用d3的name值-->
<property name="name" value="#{d3.name}"/>
</bean>
</beans>
3.复杂数据类型注入
<!--Spring复杂的数据类型注入-->
<bean id="m" class="com.weng.bean.ManTwo">
<!--数组-->
<property name="hobby">
<list>
<value>无敌1</value>
<value>无敌2</value>
<value>无敌3</value>
</list>
</property>
<!--set-->
<property name="books">
<set>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</set>
</property>
<!--list-->
<property name="phones">
<list>
<value>华为p40</value>
<value>华为p30</value>
<value>华为p20</value>
<value>华为p10</value>
</list>
</property>
<property name="map">
<map>
<entry key="川">
<value>四川</value>
</entry>
<entry key="鄂">
<value>湖北</value>
</entry>
</map>
</property>
<property name="properties">
<props>
<prop key="url">http://127.0.0.1:3306/studentdb</prop>
<prop key="username">root</prop>
</props>
</property>
</bean>
</beans>
4.实例化对象的几种方法
4.1四种方式
<?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">
<!--Spring 实例化对象的几种方法-->
<!--方法1:调用无参构造方法-->
<bean id="s1" class="com.weng.bean.Student">
<property name="id" value="1"/>
<property name="name" value="wudi2"/>
</bean>
<!--方法2:调用有参数的构造方法
type可省略
-->
<bean id="s2" class="com.weng.bean.Student">
<constructor-arg index="0" type="int" value="222"/>
<constructor-arg index="1" type="java.lang.String" value="wudi"/>
</bean>
<!--方式3:静态工厂-->
<bean id="s3" class="com.weng.bean.StudentFactory" factory-method="getStudent2">
<constructor-arg value="小王"></constructor-arg>
</bean>
<!--方式4:非静态工厂,方法非静态的
要先创建个工厂对象
-->
<bean id="studentFactory" class="com.weng.bean.StudentFactory"/>
<bean id="s4" factory-bean="studentFactory" factory-method="getStudent">
<constructor-arg value="5"></constructor-arg>
</bean>
4.2静态工厂
//静态工厂
public class StudentFactory {
static Map<String,Student> map = new HashMap<String, Student>();
static {
map.put("小周",new Student(1,"haha"));
map.put("小刘",new Student(2,"haha"));
map.put("小王",new Student(3,"haha"));
map.put("小李",new Student(4,"haha"));
}
//静态工厂要加static,非静态工厂不需要
public Student getStudent(String name){
return map.get(name);
}
public static Student getStudent2(String name){
return map.get(name);
}
}
5.传统方式和Spring创建对象对比
public class TestSpring {
//传统方式创建对象
@Test
public void test1(){
Man man = new Man();
man.setName("周星星");
man.setAge(18);
man.setAddress("吴桥");
}
//使用Spring创建对象
@Test
public void test2() throws InterruptedException {
//1.启动Spring框架,并加载配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从Spring框架容器中获取一个对象
Man m1 = context.getBean("m1", Man.class);
System.out.println(m1);
m1.setName("wudi");
Man m2 = context.getBean("m1",Man.class);
//比较地址,地址中保存的值变了
System.out.println(m1==m2);
System.out.println("person中各个方法");
Person p = context.getBean("p",Person.class);
Thread.sleep(3000);
p.setName("wuwu");
context.close();
}
}
6.注解开发
6.1xml文件配置
<?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">
<!--Spring注解开发,扫描包下的所有类,然后使用反射类上的注解,给带注解的类进行实例化-->
<context:component-scan base-package="com.weng.*"/>
<!--加载外部的配置文件-->
<context:property-placeholder location="classpath:man.properties" file-encoding="UTF-8"/>
</beans>
6.2各种注解
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component("m1")
@Scope("singleton")
/*@Component:给一个SpringIOC容器中的类生成对象,相当在xml中写了一个bean标签
默认的对象名字是类名首字母小写如:man
@Value(注入值)给属性注入值
@Autowired:自动装配,根据类型在SpringIOC容器中去匹配一个对象,如果容器中有多个类型匹配的对象,那么就会异常
数组等可以匹配多个
@Qualifier和@Autowired一起用,如果@Autowired类型匹配到了多个对象,那么使用@Qualifier人工指定具体指向哪个对象
@Resource默认是根据类型匹配IOC容器中的对象,类似@Autowired,如果匹配到多个异常
但@Resource还可以执行名字去匹配对象,@Resource还支持配置文件的写法
@Scope("singleton")单例模式property多例模式
@PostConstruct初始化方法@PreDestroy对象销毁方法
web三层:本质和@component一样
@Controller("对象名")控制创建对象,默认首字母小写
@Service,@Repository业务逻辑层和Dao层
*/
public class Man {
@Value("${man.id}")
private Integer id;
@Value("${man.name}")
private String name;
@Value("${man.sex}")
private String sex;
//ref类似用法,引用对象
//@Autowired
//@Qualifier("chineseGirl")
@Resource(name="${man.girl}")
private Igirl igirl;
//@Autowired
//private Igirl[] igirl2;
@PostConstruct
public void init(){
System.out.println("对象初始化方法");
}
@PreDestroy
public void destory(){
System.out.println("对象销毁方法");
}
}
6.3 man.properties
man.id=9527
man.name=周星驰
man.sex=男
man.girl=englishGirl
6.4 测试代码
//使用Spring-test和junit整合测试,简化开发,注解测试
@RunWith(SpringJUnit4ClassRunner.class)//使用注解的方式启动Spring框架
@ContextConfiguration("classpath:applicationContext-man.xml")//执行Spring配置文件
public class testSpring {
@Autowired
Man man;
@Test
public void test1(){
System.out.println(man.getId().toString());;
}
}
7. 代理模式
7.1基础代理理解
目标类
//目标类
@Service
public class UserServiceImpl implements UserService {
public int addUser(User user) {
System.out.println("模拟新增user到数据库"+user);
return 0;
}
public int delUser(int id) {
System.out.println("模拟从数据库删除user,删除的id为"+id);
return 0;
}
}
代理类代理目标类
//代理类
public class UserServiceProxy implements UserService {
Transaction tx = new Transaction();
UserService userService = new UserServiceImpl();//目标对象
public int addUser(User user) {
tx.openTx();
userService.addUser(user);
tx.commit();
return 0;
}
public int delUser(int id) {
tx.openTx();
userService.delUser(id);
tx.commit();
return 0;
}
}
7.2JDK动态代理
import com.weng.tx.Transaction;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//实现InvocationHandler接口 反射
public class ObjectIntercepter implements InvocationHandler {
Object target;//目标对象
public ObjectIntercepter(Object target){
this.target = target;
}
Transaction tx=new Transaction();//事务方法
//执行拦截的方法,拦截目标类中的目标方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
tx.openTx();
//调用目标对象的目标方法,反射调用方法
Object result = method.invoke(target,args);
tx.commit();
return result;
}
}
/业务逻辑层代码
public class testProxy {
UserService us=new UserServiceProxy();
@Test
public void test1(){
//真实对象
UserService target = new UserServiceImpl();
ObjectIntercepter intercepter=new ObjectIntercepter(target);
//生成一个代理类对象,此处的us不是正式的userServiceImpl对象,是代理类对象
//只能用UserService接口接收,因为不是实现类
UserService us = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),intercepter);
int i = us.addUser(new User(1, "wuw"));
System.out.println(i);
int i2 = us.delUser(1);
System.out.println(i2);
}
}
7.3Cjlib动态代理
import com.weng.tx.Transaction;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CjlibIntercepter implements MethodInterceptor {
Transaction tx = new Transaction();
//o代理对象,method子类,args参数数组,methodProxy父类
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
tx.openTx();
methodProxy.invokeSuper(o,args);
tx.commit();
return null;
}
}
//业务逻辑层代码
public class testCjlib {
UserService us=new UserServiceProxy();
@Test
public void test1(){
CjlibIntercepter h = new CjlibIntercepter();
Enhancer enhancer = new Enhancer();
//设置拦截器
enhancer.setCallback(h);
//设置要生成的子类的父类是谁
enhancer.setSuperclass(UserServiceImpl.class);
//生成子类 父类=子类
UserServiceImpl us=(UserServiceImpl)enhancer.create();
int i = us.addUser(new User(1, "wuw"));
System.out.println(i);
int i2 = us.delUser(1);
System.out.println(i2);
}
}
8. SpringAOP中5种通知类型
8.1xml配置
<!--Spring AOP(底层就是代理设计模式) XML配置-->
<!--目标target对象-->
<bean id="userServiceImpl" class="com.weng.service.impl.UserServiceImpl"/>
<!--增强类(advice 通知类) 事务类对象-->
<bean id="tx" class="com.weng.tx.Transaction"/>
<!--配置AOP-->
<aop:config>
<!--切入点:那些类的那些方法需要被植入增强代码
类中所有方法:
execution(* com.weng.service.impl.UserServiceImpl.*(..))-->
<aop:pointcut id="pointcut" expression="execution(public int com.weng.service.impl.UserServiceImpl
.addUser(com.weng.bean.User))"/>
<!--配置增强-->
<aop:aspect ref="tx">
<!--前置增强-->
<aop:before method="openTx" pointcut-ref="pointcut"/>
<!--返回增强-->
<aop:after-returning method="commit" pointcut-ref="pointcut"/>
<!--异常通知-->
<aop:after-throwing method="rollbackTx" pointcut-ref="pointcut" throwing="ex"/>
<!--最终通知-->
<aop:after method="finnalyMethod" pointcut-ref="pointcut"/>
<!--环绕通知-->
<aop:around method="arroundMethod" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
8.2注解配置
@Component
@Aspect
public class Transaction {
//切入点表达式抽取出去公用起来
@Pointcut("execution(* com.weng.service.impl.*.*(..))")
public void pointcut(){
}
//*后面要有个空格
@Before("Transaction.pointcut()")
public void openTx(){
System.out.println("开启事务");
}
@AfterReturning("execution(* com.weng.service.impl.*.*(..))")
public void commit(){
System.out.println("提交事务");
}
//异常要把throwing = "ex"写上
@AfterThrowing(value = "execution(* com.weng.service.impl.*.*(..))",throwing = "ex")
public void rollbackTx(Exception ex){
System.out.println("异常通知"+ex.getMessage());
}
@After("execution(* com.weng.service.impl.*.*(..))")
public void finnalyMethod(){
System.out.println("最终通知,释放资源等");
}
//环绕通知 joinPoint连接点是个专业术语,其实就是目标对象的封装对象
@Around("execution(* com.weng.service.impl.*.*(..))")
public Object arroundMethod(ProceedingJoinPoint joinPoint){
//调用真实的目标方法
Object result = null;
try {
System.out.println("环绕通知---前置");
result = joinPoint.proceed();
System.out.println("环绕通知---后置");
} catch (Throwable throwable) {
System.out.println("环绕通知---异常");
throwable.printStackTrace();
}finally {
System.out.println("环绕通知---最终");
}
return result;
}
}
9. Spring-Mybatis和Spring事务
9.1步骤及事务的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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/cache" 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/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--Spring和Mybatis整合的配置-->
<!--1,扫描包-->
<context:component-scan base-package="com.weng.*"/>
<!--2,加载外部配置文件-->
<context:property-placeholder location="classpath:jdbc.properties" file-encoding="utf-8"/>
<!--3,配置德鲁伊数据库连接池数据源-->
<bean id="dataSource" 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>
<!--4,配置MyBatis的SqlSessionFactory:作用给MyBatis生成sqlsession-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!--设置session工厂使用的连接池,这里是上面配置的德鲁伊数据库连接池-->
<property name="dataSource" ref="dataSource"/>
<!--设置mapper文件的位置-->
<property name="mapperLocations" value="mappers/*.xml"/>
<!--设置MyBatis的配置文件位置-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--设置MyBatis实体类别名-->
<property name="typeAliasesPackage" value="com.weng.bean"/>
</bean>
<!--5,指定Mapper接口的位置,Spring底层会给Mapper层通过代理生成对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--Spring框架会自动通过动态代理模式(反射)生成对象-->
<property name="basePackage" value="com.weng.mapper"/>
</bean>
<!--6,配置MyBatis的平台事务管理器,管理项目中的事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--
7,配置事务增强
<tx:advice id="advice">
<tx:attributes>
timeout="-1" 默认值是-1 表示默认不超时,一旦事务方法执行超过指定时间,自动回滚
read-only="false"默认值,一般的查询方法设置为只读(数据库底层会根据只读属性,进行适当的优化)
isolation="DEFAULT"当前会话的隔离级别,默认是default(数据库的默认级别)
rollback-for=""配置什么样的异常需要回滚默认值是rollback-for="java.lang.Exception"只要出异常就回滚
norollback-for则相反
propagation="REQUIRED"事务的传播特性,默认是REQUIRED
REQUIED当前没事务就新建个事务,当前有事务就按当前事务,被ty_catch包裹的异常会触发回滚
REQUIED_NEW不管当前有没有事务都用新的事务
NEVER不能有事务,有就报异常
NESTED被ty_catch包裹的异常不会触发回滚
<tx:method name="addMoney" timeout="4000"/>
</tx:attributes>
</tx:advice>
8,配置事务切面
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.weng.service.impl.*.*(..))"/>
<aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>
-->
<!--7,8换成注解配置支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
9.2mapper及mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--上述的话必须放在所有xml文件中的第一行,且不能有空格-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--接口和xml文件的名字要保持一致
namespace要是接口的全路径-->
<mapper namespace="com.weng.mapper.UserMapper">
<select id="findUsers" resultType="com.weng.bean.User">
select * from t_user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--MyBatis日志输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
9.3 事务的注解配置
@Service
@Transactional(readOnly = true)//查询配置只读事务,效率更高 方法的优先级大于类
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
//事务注解见xml7,8
//外面类写只读,类里面需要不是只读的事务设置为false
@Transactional(timeout = -1,readOnly = false, isolation = Isolation.DEFAULT,
noRollbackFor = {Exception.class,ArithmeticException.class},propagation = Propagation.REQUIRED)
public List<User> findUsers() {
return userMapper.findUsers();
}
}