基于注解的ioc
也称为DI()他是ioc的具体实现的技术
基于注解的IOC,必须要在Spring的核心配置文件中添加包扫描
<!--添加包扫描-->
<context:component-scan base-package="com.pjpower.s01"></context:component-scan>
</
-
药:创建对象并注入
-
汤:xml 注解annotation
-
创建对象注解
-
@Component:可以创建任何对象,创建的对象的默认名称是类名的驼峰命名法,也可以指定对象的名称@Component(“指定名称”)
-
@Controller:专门用来创建控制器对象(Servlet),这种对象可以接收用户的请求,可以返回结果给客户端
-
@Service专门用来创建业务逻辑层对象,负责向下访问数据访问层,处理完毕后的结果会返回给界面层
-
@Repository:专门用来创建数据访问层对象,负责数据库中的增删改查操作
-
-
依赖注入的注解
-
简单类型(八种基本类型和String类型)的注入
@Value:用来给简单类型注入值
-
引用类型的注入
-
@Autowired:使用简单类型注入值,从整个bean工厂中搜索同源类型的象进行注入
什么是同源类型?
- 被注入的类型(Student中的School)与注入类型是完全相同的类型
- 被注入的类型(Student中的School父)与注入类型(子)是父子类
- 被注入的类型(Student中的Schoo接口)与注入类型(实现类)是接口和实现类的类型
注意:在有父类的情况下,使用按类型注入,就意味着有多个可注入的对象,此时按照名称进行筛选,选中与被注入对象相同名称的对象进行注入
-
@Autowired
@Qualifior:使用名称注入值,,从整个bean工厂中搜索同源类型的象进行注入
-
添加包扫描的方式:
-
单个包扫描(推荐使用)
<context:component-scan base-package="com.bjpowernode.service.impl"></context:component-scan>
-
支持多个包扫描,多个包之间用逗号或者空格或者分号分隔
<context:component-scan base-package="com.bjpowernode.service.impl com.bjpowernode.dao.impl com.bjpowernode.controller"></context:component-scan>
-
扫描根包(不推荐,会降低容器启动速度)
<context:component-scan base-package="com"></context:component-scan>
-
为应用指定多个Spring配置文件
当项目越来越大时,需要多人共同开发,一个配置就存在很大的隐患,我们需要拆分配置文件
-
拆分配置文件的策略
-
按层拆
界面层
applicationContext_controller.xml
<bean id="uController" class="com.bjpower.controller.UserController"></bean> <bean id="bController" class="com.bjpower.controller.BookController"></bean>
业务逻辑层
applicationContext_service.xml
<bean id="uService" class="com.bjpower.cervice.UserService"></bean> <bean id="bService" class="com.bjpower.service.BookService"></bean>
数据访问层
applicationContext_mapper.xml
<bean id="uMapper" class="com.bjpower.mapper.UserMapper"></bean> <bean id="bMapper" class="com.bjpower.mapper.BookaMapper"></bean>
-
按功能拆
按用户分类
applicationContext_users.xml
<bean id="uController" class="com.bjpower.controller.UserController"></bean> <bean id="uService" class="com.bjpower.cervice.UserService"></bean> <bean id="uMapper" class="com.bjpower.mapper.UserMapper"></bean>
按书本分类
applicationContext_books.xml
<bean id="bController" class="com.bjpower.controller.BookController"></bean> <bean id="bService" class="com.bjpower.service.BookService"></bean> <bean id="bMapper" class="com.bjpower.mapper.BookaMapper"></bean>
-
Spring配置文件的整合
- 单个文件导入多个文件的导入
- 批量导入
面向切面编程AOP
AOP(Aspect Orient Programming) ,面向切面编程
切面:公共的,通用的,重复的功能称之为切面,面向切面编程就是将切面取出来,单独开发,在需要调用的方法中通过动态代理的方式进行织入。
-
手写AOP框架
业务:图书购买业务
切面:事务
- 起一个版本:业务和切面紧耦合,没有拆分
/**
* 图书购买页面和事务紧贴在一起
*/
public class BookServiceImpl {
public void buy() {
try {
System.out.println("事务开启");
System.out.println("图书购买功能的实现");
System.out.println("提交事务");
} catch (Exception e) {
System.out.println("事物的回滚");
}
}
}
- 第二个版本:使用子类代理的方式拆分业务和切面
/**
* 使用子类代理来实现业务和切面的拆分*/
public class BookServiceImpl {
public void buy(){
System.out.println("购买业务的实现");
}
}
/**
* 字类代理实现,将父类的业务添加到事物之中
*/
public class SubBookServiceImpl extends BookServiceImpl {
@Override
public void buy() {
try { //事物的开启
System.out.println("开启。。。。。。。。");
//业务的实现
super.buy();
//事物的提交
System.out.println("提交。。。。。。。。");
} catch (Exception e) {
System.out.println("事物的回滚。。。");
}
}
}
- 第三个版本:使用静态代理拆分业务和切面,此时业务和业务接口已经拆分,此使切面紧耦合在业务中
public interface Service {
//规定业务功能
void buy();
}
/**
* 目标,业务功能的具体实现
*/
public class BookServiceImpl implements Service{
@Override
public void buy() {
//
System.out.println("图书购买功能的具体实现");
}
}
/**
* 目标,业务功能的具体实现
*/
public class BookServiceImpl implements Service{
@Override
public void buy() {
//
System.out.println("图书购买功能的具体实现");
}
}
测试类:
public class Test03 {
@Test
public void test03(){
Service agent =new Agent(new BookServiceImpl());
agent.buy();
}
@Test
public void test031(){
Service agent =new Agent(new ProductServiceImpl());
agent.buy();
}
}
- 第四个版本,使用静态代理拆分业务和业务接口,切面和切面接口
public interface Service {
void buy();
}
public class BookServiceImpl implements Service{
@Override
public void buy() {
System.out.println("图书购买功能的实现。。。。。。");
}
}
public interface Aop {
//事务开启
default void before(){};
//提交事务
default void after(){};
//事务回滚
default void exception(){};
}
public class TransAop implements Aop {
@Override
public void before() {
System.out.println("事务开启。。。。。。。");
}
@Override
public void after() {
System.out.println("事务提交。。。。。。。");
}
@Override
public void exception() {
System.out.println("事务回滚。。。。。。。");
}
}
public class Agent implements Service {
public Service target;//业务对象
public Aop aop;//切面对象
public Agent(Service target, Aop aop) {
this.target = target;
this.aop = aop;
}
@Override
public void buy() {
try {
aop.before();//事物的开启
target.buy();
aop.after();//事务的提交
} catch (Exception e) {
aop.exception();//事务回滚
}
}
}
测试类:
public class Test04 {
@Test
public void test4(){
Service agent = new Agent( new BookServiceImpl(),new TransAop());
agent.buy();
}
@Test
public void test5(){
Service agent = new Agent( new BookServiceImpl(),new TransAop());
//将日志添加进去
Service agent1 =new Agent(agent,new LogAop());
agent1.buy();
}
}
- 第五个版,使用动态代理完成第四个版本的优化
public interface Service {
//规定业务功能
void buy();
//增加有参数有返回值的方法测试代理功能
default String show(int age){return null;}
}
public class BookServiceImpl implements Service {
@Override
public void buy() {
System.out.println("图书购买功能的实现。。。。。。");
}
@Override
public String show(int age) {
System.out.println("这是show 方法被调用。。。。。");
return "年龄是"+age+"岁";
}
}
public interface Aop {
//事务开启
default void before(){};
//提交事务
default void after(){};
//事务回滚
default void exception(){};
}
public class LogAop implements Aop {
@Override
public void before() {
System.out.println("前置日志输出。。。。。");
}
}
public class TransAop implements Aop {
@Override
public void before() {
System.out.println("事务开启。。。。。。。");
}
@Override
public void after() {
System.out.println("事务提交。。。。。。。");
}
@Override
public void exception() {
System.out.println("事务回滚。。。。。。。");
}
}
public class ProxyFactory {
public static Object getAgent(Service target, Aop aop) {
//返回生成的动态代理对象
return Proxy.newProxyInstance(
//类加载器
target.getClass().getClassLoader(),
//目标对象实现的所有接口
target.getClass().getInterfaces(),
//代理功能的实现
new InvocationHandler() {
@Override
public Object invoke(
//生成的代理对象
Object proxy,
//正在被调用的目标方法buy(),show()
Method method,
//设置目标方法的参数
Object[] args) throws Throwable {
Object obj = null;
try {
//切面
aop.before();
//业务
obj = method.invoke(target, args);
//切面
aop.after();
} catch (Exception e) {
//切面
aop.exception();//回滚事务
}
return obj;
}
}
);
}
}
测试类代码:
public class Test05 {
@Test
public void test05() {
//得到动态代理对象
Service agent = (Service) ProxyFactory.getAgent(new BookServiceImpl(), new TransAop());
agent.buy();
}
@Test
public void test06() {
//得到动态代理对象
Service agent = (Service) ProxyFactory.getAgent(new BookServiceImpl(), new TransAop());
//加入日志
Service agent1 = (Service) ProxyFactory.getAgent(agent, new LogAop());
String show = agent1.show(22);
System.out.println(show);
}
}
Spring 支持AOP的编程,常有以下几种:
- before通知:在目标方法被调用之前,涉及接口org.springframework.aop.MethodBeforeAdvice;
- After通知:在目标方法被调用之后调用,涉及接口org.springframework.aop.AfterReturningAdvice;
- Throws通知:目标方法抛出异常时调用,涉及接口org.springframework.aop.ThrowsAdvice;
- Around通知:拦截对目标对象方法调用,涉及接口org.springframework.aop.MethodInterceptor;
AOP常用术语:
- 切面:就是那些重复的公共的,通用的功能称之为切面,例如日志,事务,权限。
- 连接点L:就是目标方法,因为在目标方法中要实现目标方法的功能和切面功能
- 切入点(Pointcut):指定切入的位置,多个连接点构成切入点,切入点可以是一个目标方法,可以是一个类中的所有方法,也可以是某个报下所有类中的方法
- 目标对象:操作谁,谁就是目标对象
- 通知(Advice):来指定切入的时机,就是在目标方法执行前,执行后或是出错时,还是环绕目标方法切入切面功能