Spring-构造注入&注解注入&代理模式&AOP
一、spring的依赖注入方式
什么叫做注入?
一个类里面依赖于另外一个类,然后spring把类的对象创建出来,然后注入到相应的类里面过程
1.普通的注入
1)普通 set方法注入
setName(String name)
<property name="name" value="xxxx">
2.构造参数注入
1.最基本的无引用数据类型构造方法注入
//java代码构造方法案例
public MyBean1(Integer id, String name) {
this.id = id;
this.name = name;
}
方案一:根据构造方法的索引来给属性注入属性值(例)
xml中配置
<!-- 按照索引注入,索引开始为0 -->
<bean id="MyBean" class="cn.itsource._01_.MyBean">
<constructor-arg index="0" value="666" />
<constructor-arg index="1" value="张二娃" />
</bean>
方案二:根据构造方法的属性名注入属性值(例)
xml中配置
<!-- 按照名称注入,名称必须一致 -->
<bean id="MyBean" class="cn.itsource._01_.MyBean">
<constructor-arg name="id" value="1" />
<constructor-arg name="name" value="张三娃" />
</bean>
方案三:根据构造方法的属性类型注入属性值(不推荐)
xml中配置
<!-- 按照类型注入,必须一一对应,不能有重复的类型-->
<bean id="MyBean" class="cn.itsource._01_.MyBean">
<constructor-arg type="java.lang.Long" value="1" />
<constructor-arg type="java.lang.String" value="啦啦啦" />
</bean>
2.1如果有一个参数是我们自己的一个对象,怎么解决?
方法1:直接用ref引用已经定义好的bean
<bean id="otherBean" class="cn.itsource._01_.OtherBean"/>
<bean id="MyBean" class="cn.itsource._01_.MyBean">
<constructor-arg value="1" />
<constructor-arg value="啦啦啦" />
<constructor-arg ref="otherBean"/> <------------看这里
</bean>
方法2:使用一个内部的Bean完成(不需要加id,因为我们无须引用它)
<bean id="MyBean" class="cn.itsource._01_.MyBean">
<constructor-arg value="1" />
<constructor-arg value="啦啦啦" />
<constructor-arg>
<bean class="cn.itsource._01_.OtherBean"/>
</constructor-arg>
</bean>
2.2.集合(list,set,map …),数组的属性注入(有set,get方法时)
1数组的两种写法:
1.1简写
<property name="arrays" value="A,B,C" />
1.2完整写法
<property name="arrays">
<array>
<value>xxx</value>
<value>yyy</value>
<value>zzz</value>
</array>
</property>
2.List<String>
<property name="list">
<list>
<value>xxx</value>
<value>aaa</value>
<value>bbbb</value>
</list>
</property>
3.Set<String>
<property name="set">
<set>
<value>xxx</value>
<value>aaa</value>
<value>bbbb</value>
</set>
</property>
4.List<OtherBean>
<property name="otherBeanList">
<list>
<bean class="cn.itsource._01_.OtherBean" />
<bean class="cn.itsource._01_.OtherBean" />
<ref bean="otherBean" />
<ref bean="otherBean" />
</list>
</property>
5.Set<OtherBean>
<property name="otherBeanSet">
<set>
<bean class="cn.itsource._01_.OtherBean" />
<bean class="cn.itsource._01_.OtherBean" />
<ref bean="otherBean" />
<ref bean="otherBean" />
</set>
</property>
6.Map
<property name="map">
<map>
<entry key="xx" value="value1"></entry>
<entry key="yy" value="value2"></entry>
</map>
</property>
3.XML自动注入
3.1byName 按照属性的名称 setXxx方法
配置→
根节点beans default-autowire="byName" 对当前配置文件的所有bean都生效
3.2 byType按照注入对象的类型
子节点bean autowire="byType"只对当前bean生效
4.全注解配置
第一步:xml约束配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描,base-package 表示在这个配置下面的所有文件都会被spring扫描 -->
<context:component-scan base-package="cn.itsource" />
第二步:对应的类上面要加上注解
@Component 组件
@Repository 持久层(其实就是dao下面的impl实现层)
@Service service层
@Controller 控制层
第三步:在需要引用其他独享的类中 加上 @Autowired
注意:在spring中引用其他对象时,一般习惯采用引用接口的形式,spring会自己去扫描它的实现类
问题:当假如一个接口有多个实现时,spring就不能知道如何正确的引用,因此需要相应的解决办法
//在实现类上的注解中加上标识
@Repository("userJdbcDao")
public class UserJdbcDaoImpl implements IUserDao{
方案一:
@Autowired
@Qualifier("userJdbcDao")
private IUserDao userDao;
方案二:
@Resource(name="userJpaDao")
private IUserDao userDao;
哪一种更好呢?
首先@Autowired是spring中的注解,他能和Spring进行无缝衔接集成,@Resource是java中自带的注解,虽然他能解决,但是在spring中尽量用spring自己的东西
二、AOP
1.什么是aop?
定义: 面向切面编程(面向方面编程)
2.AOP术语
连接点(Joinpoint):程序执行的某一个特定位置,如类初始前后,方法的运行前后。而Spring只支持方法的连接点。
切点(Pointcut):切点可以定位到相应的连接点,一个切点可以定位多个连接点。
增强(Advice):又被称为通知,完成逻辑的增强。
目标对象(Target):增强逻辑织入的目标类。
引介(Introduction):特殊的增强,为类添加一些属性和方法。
织入(Weaving): 将增强添加到目标类的具体连接点上的过程。Spring使用动态代理织入。
代理(Proxy):一个类(原类)被织入增强(逻辑)后,就产生一个结果类,称为代理类。
切面(Aspect):由切点和增强组成
3.Spring实现AOP的方案
Spring实现Aop有两种方案:JDK代理模式与CGLIB代理模式
Xml版实现AOP
1:xml约束配置
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
xml实现aop的四种不同方式
第一种:
<bean id="txManager" class="cn.itsource.controller.TxManager"></bean>
<aop:config>
<aop:pointcut expression="execution(* cn.itsource.aop.I*Service.*(..))" id="pointcut" />
<aop:aspect ref="txManager">
<!-- 前置通知 -->
<aop:before method="begin" pointcut-ref="pointcut"/>
<!-- 后置通知 -->
<aop:after-returning method="commit" pointcut-ref="pointcut"/>
<!-- 异常通知 -->
<aop:after-throwing method="rollback" pointcut-ref="pointcut"/>
<!-- 最终通知 -->
<aop:after method="close" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
TxManager的写法
public class TxManager {
public void begin(){
System.out.println("开始了");
}
public void commit(){
System.out.println("我被提交了");
}
public void rollback(Throwable e){
System.out.println("回滚事务....");
System.out.println(e.getMessage());
}
public void close(){
System.out.println("关闭了");
}
第二种方式xml中配置环绕通知
<!--环绕通知:有了环绕,就不需要用另外几个通知(会重复) -->
<aop:around method="around" pointcut-ref="pointcut" />
TxManager的写法
public class TxManager {
public void begin(){
System.out.println("开始了");
}
public void commit(){
System.out.println("我被提交了");
}
public void rollback(Throwable e){
System.out.println("回滚事务....");
System.out.println(e.getMessage());
}
public void close(){
System.out.println("关闭了");
}
public Object around(ProceedingJoinPoint joinPoint){
Object object = null;
try {
begin();
object = joinPoint.proceed(); //执行相应的代码
commit();
} catch (Throwable e) {
rollback(e);
}finally{
close();
}
return object;
}
第三种:.注解版
xml配置
<!-- 组件搜索 -->
<context:component-scan base-package="cn.itsource.aopanno" />
<!-- 支持aop注解 -->
<aop:aspectj-autoproxy />
注解用法
@Component
@Aspect //AOP的类注解
public class TxManager {
//设置切点
@Pointcut("execution(* cn.itsource.aopanno.I*Service.*(..))")
public void pointcut(){}
//前置通知
@Before("pointcut()")
public void begin(){
System.out.println("开启事务....");
}
//后置通知
@AfterReturning("pointcut()")
public void commit(){
System.out.println("提交事务...");
}
//异常通知
@AfterThrowing(pointcut="pointcut()",throwing="e")
public void rollback(Throwable e){
System.out.println("回滚事务....");
System.out.println(e.getMessage());
}
//最终通知
@After("pointcut()")
public void close(){
System.out.println("关闭资源....");
}
}
第四种:注解版的round写法
@Component
@Aspect //AOP的类注解
public class TxManager2 {
//设置切点
@Pointcut("execution(* cn.itsource.controller.I*ServiceDao.*(..))")
public void pointcut() {
}
public void begin() {
System.out.println("开始了");
}
public void commit() {
System.out.println("我被提交了");
}
public void rollback(Throwable e) {
System.out.println("回滚事务....");
System.out.println(e.getMessage());
}
public void close() {
System.out.println("关闭了");
}
@Around("pointcut()") <--------------------------------------------重点变化
public Object around(ProceedingJoinPoint joinPoint) {
Object object = null;
try {
begin();
object = joinPoint.proceed(); //执行相应的代码
commit();
} catch (Throwable e) {
rollback(e);
} finally {
close();
}
return object;
}
}