一、Spring的IOC的注解开发(*)
1、Spring的IOC的注解开发入门
(1)、创建web项目,引入jar包
- 在spring4的版本中,除了引入基本开发包以外,还需要引入aop的包。
(2)、引入Spring的配置文件
- 在src下创建applicationContext.xml.
- 引入约束:使用注解开发,需要引入context约束。
- 约束:spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
<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 definitions here -->
</beans>
(3)、创建接口和实现类
(4)、开启Spring的组件扫描
<!-- 使用IOC的注解开发,配置组件扫描(哪些包下的类需要使用IOC注解) -->
<context:component-scan base-package="cn.itcast.spring.demo1"/>
(5)、在类上添加注解
@Component("userDao") // 相当于<bean id="userDao" class="cn.itcast.spring.demo1.UserDaoImpl"/>
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("Dao中保存用户的方法执行了。。。");
}
}
(6)、编写测试类
@Test
// Spring的IOC的注解方式
public void demo2() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
(7)、注解方式设置属性的值
- 注解方式:使用注解方式,可以没有set方法。
- 属性如果有set方法,需要将属性注入的注解添加到set方法上。
- 属性如果没有set方法,需要将属性注入的注解添加到属性上。
@Component("userDao") // 相当于<bean id="userDao" class="cn.itcast.spring.demo1.UserDaoImpl"/>
public class UserDaoImpl implements UserDao {
@Value("bbb")
private String name;
/*@Value("bbb")
public void setName(String name) {
this.name = name;
}*/
@Override
public void save() {
System.out.println("Dao中保存用户的方法执行了。。。" + name);
}
}
2、Spring的IOC的注解的详解
(1)、@Component:组件
- 修饰一个类,将这个类交给Spring管理。
- 这个注解有是三个衍生注解(功能类似),修饰类
- @Controller:web层
- @Service:service层
- @Repository:dao层
(2)、属性注入的注解
- 普通属性:
- @Value:设置普通属性的值。
- 对象类型属性:
- @Autowired:这只对象类型的属性的值。但是按照类型完成属性注入。
- 习惯上按照名称完成属性注入:必须让@Autowired注解和@Qualifier(value=“xxx”)一起使用完成按照名称属性注入。
- @Resource:完成对象类型的属性注入,按照名称完成属性注入。
(3)、Bean的其他的注解
- 生命周期的相关注解(了解)
- PostConstruct:初始化方法
- PreDestory:销毁方法
- Bean的作用范围的注解:
- @scope:作用范围
- singleton:默认单例
- prototype:多例
- request
- session
- globalsession
3、IOC的XML和注解的比较
- 使用场景
- XML:可以使用任何场景–结构清晰,维护方便。
- 注解:有些地方用不了,这个类不是你自己提供的。–开发方便
- XML和注解整合开发
- XML管理Bean,注解完成属性注入
注意:
- 如果类上加了注解,需要开启扫描。
<context:component-scan base-package="..."/>
- 如果类上没有加注解,也可以使用属性注入,如:@Resources、@Value、@AutoWired、@Qulifier,需要开启:
<context:annotation-config/>
二、Spring的AOP的XML开发(*)
1、AOP概述
(1)、什么是AOP
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。—百度百科
AOP:面向切面编程。AOP是OOP的扩展和衍生,解决OOP开发遇到的问题。
(2)、Spring的底层的AOP实现原理
- 动态代理
- JDK动态代理:只能对于实现了接口的类产生代理。
- Cglib动态代理(类似于Javassist第三方代理技术):对没有实现接口的类产生代理对象。生成子类对象。(不用final修饰)
2、Spring的AOP底层实现(了解)
(1)、JDK动态代理
public class JdkProxy implements InvocationHandler{
// 将被增强的对象传递到代理中
private UserDao userDao;
public JdkProxy(UserDao userDao) {
this.userDao = userDao;
}
// 产生UserDao代理的方法
public UserDao createProxy() {
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(), this);
return userDaoProxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断方法名是不是save
if("save".equals(method.getName())) {
// 增强
System.out.println("权限校验");
return method.invoke(userDao, args);
}
return method.invoke(userDao, args);
}
}
(2)、Cglib动态代理
- Cglib:第三方开源代码生成库,动态添加类的属性和方法。
public class CglibProxy implements MethodInterceptor{
private CustomerDao customerDao;
public CglibProxy(CustomerDao customerDao) {
this.customerDao = customerDao;
}
// 使用Cglib产生代理方法
public CustomerDao createProxy() {
// 1、创建Cglib的核心对象
Enhancer enhancer = new Enhancer();
// 2、设置父类
enhancer.setSuperclass(customerDao.getClass());
// 3、设置回调(类似于InvocationHandler)
enhancer.setCallback(this);
// 4、创建代理对象
CustomerDao proxy = (CustomerDao) enhancer.create();
return proxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
// 判断是否为save
if ("save".equals(method.getName())) {
// 增强
System.out.println("权限调用++++");
return methodProxy.invokeSuper(proxy, args);
}
return methodProxy.invokeSuper(proxy, args);
}
}
3、Spring的AOP的开发(AspectJ的XML的方式)
(1)、AOP开发中的相关术语:
- Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点
- Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
- Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
- Aspect(切面): 是切入点和通知(引介)的结合
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field. - Target(目标对象):代理的目标对象(要增强的类)
- Weaving(织入):是把增强应用到目标的过程.
- 把advice 应用到 target的过程
- Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
4、Spring的APO的入门(AspectJ的XML的方式)
(1)、创建web项目,引入jar包
- 引入基本的开发包
- 引入aop开发的相关jar包
(2)、引入Spring的配置文件
- 引入aop约束
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
(3)、编写目标类并完成配置
<!-- 配置目标对象:被增强的对象 -->
<bean id="productDao" class="cn.itcast.spring.demo3.ProductDaoImpl"></bean>
(4)、编写测试类
- Spring整合Junit单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
@Resource(name="productDao")
private ProductDao productDao;
@Test
public void demo1() {
productDao.save();
productDao.update();
productDao.delete();
productDao.find();
}
}
(5)、编写一个切面类
- 编写切面类
// 切面类
public class MyAspectXML {
public void checkPri() {
System.out.println("权限校验====");
}
}
- 将切面类交给Spring
<!-- 将切面类交给Spring管理 -->
<bean id="myAspect" class="cn.itcast.spring.demo3.MyAspectXML"/>
(6)、通过AOP配置实现
<!-- 通过AOP的配置完成目标类产生代理 -->
<aop:config>
<!-- 表达式配置哪些类的那些方法需要进行增强 -->
<aop:pointcut expression="execution(* cn.itcast.spring.demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
5、Spring中通知的类型
所有通知都可以获得切入点信息。
(1)、前置通知:在目标方法执行之前进行操作
- 前置通知:可以获得切入点信息
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>
(2)、后置通知:在目标方法执行之后进行操作
- 后置通知:获得方法的返回值。
<!-- 后置通知 -->
<aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
(3)、环绕通知:在目标方法执行之前和之后进行操作
- 环绕通知可以阻止目标方法的执行。
- XML文件
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
- 切面类
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前===");
Object obj = proceedingJoinPoint.proceed();
System.out.println("环绕后===");
return obj;
}
(4)、异常抛出通知:在程序出现异常的时候,进行操作
- 可以得到异常的信息。
- XML配置文件
<!-- 异常抛出通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
- 切面类
// 异常抛出
public void afterThrowing(Throwable ex) {
System.out.println("异常抛出===" + ex.getMessage());
}
(5)、最终通知:无论代码是否有异常,总会执行。
<!-- 最终通知 -->
<aop:after method="after" pointcut-ref="pointcut4"/>
(6)、引介通知(暂时不用)
6、Spring的切入点表达式写法
(1)、切入点表达式语法:
- 基于execution的函数完成的
- 语法
- [访问修饰符] 方法返回值 包名.类名.方法名(参数)
- public void cn.itcast.spring.CustomerDao.save(…)
- * *.*.*.*Dao.save(…)
- * cn.itcast.spring.CustomerDao+.save(…):“+”指当前的类和其子类。