一、自动装配(xml方式、不推荐)
1.一般方式
<bean id="otherBean" class="spring_autowired_xml.OtherBean" />
<bean id="someBean" class="spring_autowired_xml.SomeBean">
<property name="otherBean" ref="otherBean" />
</bean>
2.自动装配
<bean autowire="" />
-default :不自动注入
-no :不自动注入
-byName :按照名字注入(按照属性的名字在spring中找bean)
-byType :按照依赖对象的类型注入
-constructor:按照对象的构造器上面的参数类型注入
注意:
1,如果按照byName自动注入,要求所有的属性名字和id的名字必须保证一种规范的命名方式;
2,如果按照byType注入,如果spring中同一个类型有多个实例----报bean不是唯一类型错误;
<bean id="otherBean" class="spring_autowired_xml.OtherBean" />
<bean id="someBean" class="spring_autowired_xml.SomeBean" autowire="byType" />
<bean id="otherBean" class="spring_autowired_xml.OtherBean" />
<bean id="someBean" class="spring_autowired_xml.SomeBean" autowire="byName" />
二、自动装配(注解方式)
<?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
">
<bean id="otherBean" class="spring_autowired_ann.OtherBean" />
<bean id="otherBean2" class="spring_autowired_ann.OtherBean2" />
<bean id="someBean" class="spring_autowired_ann.SomeBean"/>
</beans>
public class SomeBean {
//@Autowired
private OtherBean otherBean;
//@Autowired
private OtherBean2 otherBean2;
@Autowired
public void setXXX(OtherBean otherBean,OtherBean2 otherBean2){
this.otherBean = otherBean;
this.otherBean2 = otherBean2;
}
@Override
public String toString() {
return "SomeBean [otherBean=" + otherBean + ", otherBean2="
+ otherBean2 + "]";
}
}
1,@Autowired标签:
1,通过@Autowired标签可以让spring自动的把属性需要的对象从容器中找出来,并注入给对象.
2,autowired标签可以放在字段或者setter方法上面
3,使用autowired标签可以注入一些spring内置的重要对象,比如BeanFactory,ApplicationContext;
4,默认情况下,@Autowired标签必须要能找到对应的对象,否则报错;通过required=false来避免这个问题:@Autowired(required=false)
5,@Autowired找bean的方式:
1),首先按照依赖对象的类型找;如果找到,就是用setter或者字段直接注入;
2),如果在Spring上下文中找到多个匹配的类型,再按照名字去找;如果没有匹配,报错;
3),可以通过使用@Qualifier(“otherBean”)标签来规定依赖对象按照bean的id+类型去找;
2,@Resource标签:
1,@Resource标签是JavaEE规范的标签;
2,@Resource标签也可以作用于字段或者setter方法;
3,也可以使用@Resource标签注入一些spring内置的重要对象,比如BeanFactory.ApplicationContext;
4,@Resource必须要求有匹配的对象;
5,<context:annotation-config>
既引入了@Autowired标签的解析器,也引入了@Resource的解析器;
6,@Resource标签找bean的方式:
1),首先按照名字去找,如果找到,就使用setter或者字段注入;
2),如果按照名字找不到,再按照类型去找,但如果找到多个匹配类型,报错;
3),可以直接使用name属性指定bean的名称;但是,如果指定的name,就只能按照name去找,如果找不到,就不会再按照类型去找;
3,@Autowired标签和@Resource标签如何择选
1.@Autowired是Spring的标签,使用,和Spring耦合,有可能有未知的错误.---Spring
2,@Resouce:是J2EE的规范,所以稳定,在J2EE规范容器中也能正常使用;
三、使用注解简化IoC
<?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
">
<!--
@Component:把该对象交给Spring进行管理
扫描哪些包及其子包中@Component注解
若要扫描多个包,用逗号分隔,也可以定义多个<context:component-scan base-package=""/>
-->
<context:annotation-config />
<context:component-scan base-package="spring_ann_IoC" />
</beans>
package spring_ann_IoC;
import org.springframework.stereotype.Component;
@Component
public class OtherBean {
}
package spring_ann_IoC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class SomeBean {
@Autowired
@Qualifier("otherBean")
//@Qualifier("sb")
private OtherBean otherBean;
@Override
public String toString() {
return "SomeBean [otherBean=" + otherBean + "]";
}
}
1.标注Bean的注解:@Component
默认情况,直接使用类的名字(首字母小写作为bean的名字)
如果要修改bean的名称;直接使用value属性来重新定义bean的名称
OtherBean类
package spring_ann_IoC;
import org.springframework.stereotype.Component;
@Component("sb")
public class OtherBean {
}
SomeBean类
@Component
public class SomeBean {
@Autowired
//@Qualifier("otherBean")
@Qualifier("sb")
private OtherBean otherBean;
@Override
public String toString() {
return "SomeBean [otherBean=" + otherBean + "]";
}
}
2.使用@Component的限制:
1),不能运用到静态工厂方法和实例工厂方法,但是可以使用到FactoryBean;
2),对于没有源代码的类(框架内部的预定义类),只能用XML配置;
3.是否是单例的
在我们自己用xml配置bean的时候我们可以设置Scope对于注解方式如何实现?
注解方式默认也是单例的。
我们只需要设置@Scope(“prototype”)
@Component
@Scope("prototype")
public class SomeBean {
@Autowired
//@Qualifier("otherBean")
@Qualifier("sb")
private OtherBean otherBean;
@Override
public String toString() {
return "SomeBean [otherBean=" + otherBean + "]";
}
}
3.初始化和销毁
@PostConstruct
public void init(){
System.out.println("init()...........");
}
@PreDestroy
public void destroy(){
System.out.println("destroy........");
}
4.bean组件版型标签
bean组件版型:
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)、
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
bean组件版型用法和@Component一样,仅仅是名字不同,用的地方不同。
三、代理
1.静态代理
1,代理对象完全包含真实对象,客户端使用的都是代理对象上面的方法,和真实对象无关;
2,静态代理能够处理:
1),把不是真实对象该做的事情从真实对象上面撇开;
3,静态代理带来的问题:
1),还是需要在每一个方法上面处理额外的业务;业务代码(大家都需要做的事情,公共的事情)还是分散在各个方法中的;
2),需要为每一个真实对象都得创建一个代理对象
public interface Rent {
public void rent();
}
Host
public class Host implements Rent {
@Override
public void rent() {
System.out.println("出租房屋。。。。。。");
}
}
Proxy
public class Proxy implements Rent{
private Host host;
@Override
public void rent() {
seeHouse();
host.rent();
fee();
}
public void seeHouse(){
System.out.println("看房。。。。");
}
public void fee(){
System.out.println("收费.....");
}
public void setHost(Host host) {
this.host = host;
}
}
配置文件
<?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
">
<bean id="host" class="cn.bdqn.staticproxy01.Host"></bean>
<bean id="proxy" class="cn.bdqn.staticproxy01.Proxy">
<property name="host" ref="host"></property>
</bean>
</beans>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TestStaticProxy {
@Autowired
private ApplicationContext ac;
@Test
public void testAnnIoC(){
Proxy proxy = ac.getBean("proxy",Proxy.class);
proxy.rent();
}
}
2.动态代理(JDK)
JDK动态代理:
1,我代理的对象必须要实现一个接口;
2,需要为每个对象创建代理对象;
3,动态代理的最小单位是类(所有类中的方法都会被处理);
public interface Rent {
public void rent();
}
Host
public class Host implements Rent {
@Override
public void rent() {
System.out.println("出租房屋。。。。。。");
}
}
动态代理类
public class PynamicProxy implements InvocationHandler{
private Object target; //真是目标对象
//创建代理对象
public Object createProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
//执行增强操作
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
seeHouse();
Object result = method.invoke(target, args);
fee();
return result;
}
public void seeHouse(){
System.out.println("看房。。。。。。");
}
public void fee(){
System.out.println("收费。。。。。。");
}
public void setTarget(Object target) {
this.target = target;
}
}
配置文件
<?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
">
<bean id="host" class="cn.bdqn.dynamicproxy.jdk01.Host"></bean>
<bean id="proxy" class="cn.bdqn.dynamicproxy.jdk01.PynamicProxy">
<property name="target" ref="host"></property>
</bean>
</beans>
测试
public class TestPynamicProxy {
@Autowired
@Qualifier("proxy")
private PynamicProxy proxy;
@Test
public void testPynamicProxy(){
Rent p= (Rent)proxy.createProxy();
p.rent();
}
}
JDK动态代理总结:
1,JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。
2,要使用JDK动态代理,必须要定义接口。
3,JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。
4,如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断。
2.动态代理(CGLib)
若一个类,没有接口如何代理?
javassist.jar:Hibernate和Struts2的代理实现方案.
cglib.jar:Spring的代理实现方案:
实现类
public class EmployeeServiceImpl{
public void save() {
System.out.println("------保存员工------");
}
}
事务管理类
/**
* 事务管理器
* @author Administrator
*
*/
public class TransactionManager {
public void beginTransaction(){
System.out.println("开启事务。。。。");
}
public void commit(){
System.out.println("提交事务。。。。");
}
public void rollback(){
System.out.println("回滚事务。。。。");
}
}
代理类
public class ProxyCallBack implements org.springframework.cglib.proxy.InvocationHandler {
private Object target; //真实对象
private TransactionManager txManager;
//创建代理对象
public Object createProxy(){
//增强器
Enhancer enhancer = new Enhancer();
//把真实对象作为代理父类
enhancer.setSuperclass(target.getClass());
//设置增强的操作
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
//执行增强操作
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
txManager.beginTransaction();
try {
obj= method.invoke(target, args);
txManager.commit();
} catch (Exception e) {
txManager.rollback();
}
return obj;
}
public void setTarget(Object target) {
this.target = target;
}
public void setTxManager(TransactionManager txManager) {
this.txManager = txManager;
}
}
测试
@Autowired
private ProxyCallBack proxy;
@Test
public void testStaticProxy(){
EmployeeServiceImpl p = (EmployeeServiceImpl)proxy.createProxy();
p.save();
}
CGLIB代理总结:
1,CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。
2,要求类不能是final的,要拦截的方法要是非final、非static、非private的。
3,动态代理的最小单位是类(所有类中的方法都会被处理);
代理总结:
Spring中:
1,若目标对象实现了若干接口,spring就会使用JDK动态代理。
2,若目标对象没有实现任何接口,spring就使用CGLIB库生成目标对象的子类。
四、AOP
1.1. AOP—Aspect Oriented Programming
面向切面编程——弥补面向对象编程(OOP)的不足
AOP和IOC是Spring的两个核心。AOP是对IOC的补充,他们之间不存在依赖关系。
2. AOP的作用
提供显式的事物管理
允许用户自定义切面
3. AOP的优点
通过静态代理可以使业务类更加纯粹
公共业务由代理完成—实现分工
公共业务高度集中便于扩展和修改
4. 名词
1.关注点:除正常业务以外需要重点注意的事项。如:日志、同步等业务。
2.连接点(Joinpoint):特定方法的调用就可以称为连接点
3.切入点:Pointcut:在哪些类,哪些方法上面切(where);
4.通知/增强Advice:在方法的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);连接点上特定方法执行的动作就称为通知
通知可以分为前置通知(Before advice)、后置通知(After returning advice)、环绕通知(Around Advice)、异常通知(After throwing advice)、最终通知(After (finally) advice)
5.切面(Aspect):一个关注点的模块化就称为切面。也就是切入点+通知: 什么时机,什么地点,干啥!
6.,织入Weaving:把切面加入到对象,并创建出代理对象的过程.(Spring来做的)
5.AOP的配置(xml)
1,依赖的jar包
spring-aop-4.3.3.RELEASE.jar
aopalliance.jar
aspectjweaver.jar
2,引入aop命名空间
3,aop配置
什么时机:什么地点,做什么
<aop:config>
<aop:aspect ref="txManager">:做什么
<aop:pointcut expression="execution(* cn.itcast.cd.day2._6aop_xml.*Service.*(..))" id="txPoint"/>:什么地点(哪些方法上)
<aop:before method="beginTransaction" pointcut-ref="txPoint"/>:时机:方法前/方法后/方法前后
4,aspectJ
AOP思想广泛应用于java,专门有一个组织负责aop的一切事物(AOP联盟)
首先就要解决一个问题,怎么表示在那些方法上切。---->aspectJ(语言)
通过表达式语言在那些包下那些类中的那些方法上切(增强)
5,实现
接口
public interface IEmployeeService {
public void save();
}
实现
public class EmployeeServiceImpl implements IEmployeeService {
@Override
public void save() {
System.out.println("------保存员工------");
throw new RuntimeException("出现异常");
}
}
事务管理类
/**
* 事务管理器
* @author Administrator
*
*/
public class TransactionManager {
//在业务方法被调用前,如何获取业务方法的信息
public void beginTransaction(JoinPoint jp){
System.out.println("开启事务。。。。");
//void cn.bdqn.aop_xml.IEmployeeService.save()
//System.out.println(jp.getSignature()); //得到方法的签名
//System.out.println(jp.getTarget()); //真是主题对象
//System.out.println(jp.getArgs()); //方法参数
}
public void commit(){
System.out.println("提交事务。。。。");
}
public void rollback(Throwable ex){
System.out.println("回滚事务。。。。");
System.out.println(ex.getMessage());
}
public void close(){
System.out.println("关闭Session。。。。");
}
/*//环绕业务方法的增强
//如何调用真正的业务方法
public void around(){
System.out.println("开启事务");
try {
System.out.println("执行业务方法。。");
System.out.println("提交事务");
} catch (Exception e) {
System.out.println("回滚事务");
}finally{
System.out.println("关闭Session");
}
}*/
//调用真正的业务方法,真正的业务方法可能有返回值
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("开启事务");
try {
Object result = pjp.proceed(); //调用业务方法
System.out.println("提交事务");
return result;
} catch (Exception e) {
System.out.println("回滚事务");
}finally{
System.out.println("关闭Session");
}
return null;
}
}
<?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: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
">
<!--
AOP思想广泛应用于java,专门有一个组织负责aop的一切事物(AOP联盟)
首先就要解决一个问题,怎么表示在那些方法上切。 aspectJ(语言)
通过表达式语言在那些包下那些类中的那些方法上切(增强)
-->
<bean id="txManager" class="cn.bdqn.aop_xml.TransactionManager" />
<bean id="employeeService" class="cn.bdqn.aop_xml.EmployeeServiceImpl" />
<aop:config>
<aop:aspect ref="txManager">
<aop:pointcut expression="execution(* cn.bdqn.aop_xml.*Service.*(..))" id="txManagerPoint"/>
<!-- 前置通知:在业务方法执行之前执行增强操作(增强类中的指定增强方法) -->
<aop:before method="beginTransaction" pointcut-ref="txManagerPoint"/>
<!-- 后置通知:在业务方法成功调用之后增强操作
<aop:after-returning method="commit" pointcut-ref="txManagerPoint"/>-->
<!--
异常通知:在业务方法中出现异常,需要调用增强操作
throwing="ex":决定方法定义为:public void rollback(Throwable ex)
<aop:after-throwing method="rollback" pointcut-ref="txManagerPoint"
throwing="ex"
/>-->
<!-- 最终通知:finally里的,都要制定增强操作
<aop:after method="close" pointcut-ref="txManagerPoint"/>-->
<!-- 环绕通知:前4个的综合,环绕着业务方法的增强
<aop:around method="around" pointcut-ref="txManagerPoint"/>-->
</aop:aspect>
</aop:config>
</beans>
Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AopTest {
@Autowired
private IEmployeeService service;
@Test
public void testAop(){
service.save();
}
}